【问题标题】:Is it bad to use redundant relationships?使用冗余关系不好吗?
【发布时间】:2010-07-27 19:10:11
【问题描述】:

假设我的数据库中有以下表格:

现在我所有的查询都依赖于 Company 表。为所有其他表提供与 Company 表的(冗余)关系以简化我的 sql 查询,这是一种不好的做法吗?

编辑 1: 背景是框架的使用问题。见Django: limiting model data

编辑 2:没有元组会改变他的公司。

编辑 3: 我不编写 mysql 查询。我使用抽象层(django)。

【问题讨论】:

  • “关系”这个词并不意味着你显然想要它的意思。关系数据库模型中的relation 对应于大多数人所说的表。它与不同表中数据之间的关系无关。
  • 是的,你是对的。我已经更正了。
  • @SvenWalter 请使用代码块 (<pre></pre>) 中的表格更新问题,因为外部图像文件不再可用。我分享了在 SE 中没有合适的表的痛苦(开发人员一直坚持不让它可用),但至少我们可以用代码块来模拟它们,而不是依赖外部工具。

标签: database database-design relational-database


【解决方案1】:

这是一种不好的做法,因为您的冗余数据必须独立更新,因此是冗余的。一个充满潜在错误的过程。 (即使是自动级联也必须单独分配和维护)

通过引入这种关系,您可以有效地非规范化您的数据库。出于性能考虑,有时需要非规范化,但从您的问题看来,您只是在简化 SQL。

使用其他机制来抽象数据库的复杂性:视图、存储过程、UDF

【讨论】:

  • 许多 RDBM 都有级联更新。更改公司表中的公司 ID 将级联到引用它的所有表。
  • siride:这是一个很好的观点,但是保持链接的可级联性仍然是一个额外的维护步骤,必须完成并且必须正确完成。在我的书中越简单越好。坚持使用外键,并在查询中使用额外的 JOIN。
  • 我认为这是个坏主意。感谢您的帮助...我必须找到其他解决方案。
  • 这并不总是一个坏习惯。例如,在处理多租户时使用租户标识符这样做是很常见的——因为它不会改变(不包括租户合并和类似的稀有东西),缺点或多或少不存在。另一个有效的用例是出于性能原因进行非规范化。
  • 如果您有大型子表,则不应使用 PLus 级联更新,因为这可能会导致严重的性能问题。
【解决方案2】:

您要问的是您的设计是否违反了第三范式。这样做不是没有充分理由的事情,因为通过创建冗余,您可能会在数据中产生错误和不一致。此外,使用冗余数据“简化”模型以支持某些操作可能会使其他操作复杂化。此外,可能需要不必要地复制约束和其他数据访问逻辑。

【讨论】:

    【解决方案3】:

    为每个其他表提供与 Company 表的(冗余)关系以简化我的 sql 查询,这是一种不好的做法吗?

    是的,当然,因为这意味着当您将关系客户更新到公司或部门更新到公司时,更新每个冗余关系 - 如果您错过任何此类更新,您现在拥有一个充满冗余数据的数据库。这是一个糟糕的非规范化。


    如果您只是为了简化 SQL,请考虑使用视图来“带来”父数据。这是通过客户加入将 company_id 拉入合同的视图:

    create view contract_customer as
    select 
      a.*, 
      b.contract_id, b.company_id
    from 
      contract a 
      join customer b on (a.customer_id = b.customer_id);
    

    这个连接很简单,但为什么要一遍又一遍地重复呢?编写一次,然后在其他查询中使用该视图。

    如果您不将来自客户的任何列放在选择列表或基于视图的查询的 where 子句中,许多(但不是全部)RDBMS 甚至可以优化连接,只要您使 contract.customer_id 具有customer.customer_id 上的外键引用完整性约束。 (在没有这样的约束的情况下,不能省略连接,因为它可能会存在一个在客户中不存在的 contract.customer_id。因为你永远不会想要 那个,您将添加外键约束。)

    使用视图可以实现您想要的,无需更新子表的时间开销,也无需通过添加冗余列使子行变宽的空间开销(当您有很多行时,这真的很重要,行越宽,一次可以放入内存的行就越少),最重要的是,当父更新而子不更新时,不会出现不一致的数据。

    【讨论】:

      【解决方案4】:

      如果您真的需要简化事情,View(或多个视图)会派上用场。

      如果您的员工视图中有一个公司列,则不会因为它是从连接部分派生而来的,那么规范化效果不会很差。

      【讨论】:

        【解决方案5】:

        如果您的意思是向每个表中添加公司列,那么这是一个坏主意。它会增加数据完整性问题的可能性(即它在一个表中被更改,但在其他 6 个表中没有更改)。

        【讨论】:

          【解决方案6】:

          我会说不是在 OP 的情况下,但有时它很有用(就像 goto ;)。

          一则轶事:

          我正在使用一个数据库,其中大多数表都有一个指向帐户根表的外键。帐号在数据库之外,一旦发出就不允许更改。因此,不存在更改帐号和无法更新数据库中所有引用的危险。我还发现,从以帐号为键的表中获取数据也相当容易,而不必进行复杂且昂贵的连接层次结构以获取根帐户表。但就我而言,我们没有那么多外键作为外部(即现实世界)标识符,所以它与 OP 的情况不太一样,似乎适合例外情况。

          【讨论】:

            【解决方案7】:

            这取决于您对“性能”的功能要求。您的应用程序会处理大量需求吗?简化 JOINS 具有性能。此外,硬件便宜且周转时间很重要。

            你在数据库范式中走得越深——你节省空间但计算量很大

            【讨论】:

            • 如果索引正确,在连接导致性能问题之前,您必须拥有庞大的数据库。奇怪的是,我认识的管理具有数万亿条记录的数据库的人仍然使用联接,但那是因为这些类型系统的数据库设计人员很称职。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-20
            • 2020-01-26
            • 2014-09-28
            相关资源
            最近更新 更多