【问题标题】:Can foreign keys hurt query performance外键会损害查询性能吗
【发布时间】:2010-12-17 05:21:26
【问题描述】:

据我从this post 了解到,在某些情况下外键可以提高查询性能。

不过,我听到了相反的说法,即由于参照完整性检查,外键实际上会损害查询性能。在什么条件下(如果有的话)是这样的?


1) 术语查询似乎具有误导性。我对各种性能惩罚感兴趣。

2) 是否有人对 INSERT、DELETE 或 UPDATE 语句的负面影响有任何真实的数字(我知道这取决于特定的系统,但是任何类型的真实测量都会受到赞赏)?

【问题讨论】:

  • “查询”是指选择吗?因为我认为参照完整性检查只会影响 INSERT/UPDATE/DELETE 在性能方面。

标签: sql-server-2005


【解决方案1】:

如果引用完整性需要外键,那么外键的存在应该构成性能的基线

你不妨问一下,如果你不把座位放进去,汽车是否能跑得更快——一辆结构良好的汽车包括座位,就像一个结构良好的数据库包括外键一样

【讨论】:

    【解决方案2】:

    我假设对于 INSERT 查询,约束(包括外键约束)会在一定程度上降低性能。数据库必须检查你告诉它插入的任何东西是你的约束允许它插入的东西。

    对于 SELECT 查询,外键约束不应对性能做出任何改变。

    由于 INSERTS 几乎总是非常快,因此少量的额外时间不会引起注意,除非是在边缘情况下。 (构建一个几GB的数据库,你可能想禁用约束,然后再重新启用,只要你确定数据是好的。)

    【讨论】:

      【解决方案3】:

      理论上,是的:数据写入需要验证约束。

      在实践中,很少:除非以其他方式衡量和证明,否则您可以假设对性能没有影响。绝大多数情况下,性能问题是由其他问题引起的:

      • 糟糕的架构设计(缺少索引,错误的聚集索引选择)
      • 争用(阻塞),同样是由于架构设计错误(表扫描保证锁冲突)
      • 糟糕的查询设计

      在设计良好的架构和良好的查询上,约束成本将开始以非常高吞吐量出现。发生这种情况时,有预防措施。

      我的 2c:从不为了一些难以捉摸的性能目标而牺牲正确性约束。在非常罕见的情况下,约束确实是问题,有测量表明情况确实如此,俗话说:如果你不得不问它的成本是多少,你买不起。如果您必须询问约束是否会成为问题,则不能删除它们(无意冒犯)。

      【讨论】:

      • 同意。虽然性能对数据库来说确实很重要,但它永远不应该胜过数据完整性。什么需要快速插入不可靠的数据?
      【解决方案4】:

      外键可能会导致子表中的插入(或某些更新)或从父表中删除需要更长时间。这是一件好事,因为这意味着它确保数据完整性保持不变。除非您不想拥有有用的数据,否则没有任何理由跳过使用外键。除非您将许多外键关联到同一个父表,或者如果您在一批中插入或删除许多记录,否则您通常不会注意到太大的差异。此外,我注意到,用户在插入或删除中比在选择中更能容忍几秒钟的额外时间。用户也完全不能容忍不可靠的数据,这是您在没有外键约束的情况下所拥有的。

      您需要将它们编入索引以提高选择查询的性能。

      【讨论】:

        【解决方案5】:

        对于 INSERT/UPDATE/DELETE,简短的回答是“是”。数据库将需要检查参照完整性是否完好,并且允许创建/修改。或者在 DELETE 的情况下,可能需要进行一些级联操作。

        对于 SELECT,实际上恰恰相反。外键有一个秘密的附加好处,它可以准确地向您显示您最有可能在哪里进行复杂的 JOIN,并且具有非常常用的字段。这使得索引工作变得更加容易,并且您几乎可以保证您的所有 FK 字段都应该被索引。这使得 SELECTs 快得多

        【讨论】:

          【解决方案6】:

          外键检查花费的时间比大多数人想象的要长。当前对 Oracle 11g 和具有两个外键的表的测试表明,插入大约 800.000 行的时间在启用外键的情况下需要 60 秒,但在没有外键的情况下只需 20 秒。 (当然,外键列被索引了)

          无论如何,我同意所有其他发帖者的观点,完整性约束不是一种选择,而是保持数据一致的唯一方法。但是,对于导入,尤其是对空表的导入,如果时间紧迫,可以选择在导入时禁用外键。

          【讨论】:

          • 在涉及一组批量插入的情况下,可以为插入禁用外键,然后在插入后重新启用。有效性扫描将验证没有插入的值违反规则。如果有人这样做,他们可以单独处理——他们必须是任何一种方式。
          【解决方案7】:

          如果外键以这种方式产生任何影响,它会在 INSERTS 上。数据库在创建/修改记录时对外键进行引用检查,而不是选择。

          【讨论】:

            【解决方案8】:

            外键在大多数情况下不会影响查询性能,强烈推荐。通过帮助规范化,您将消除冗余数据,并且如果您通过添加底层索引(针对适当的外键)进行跟进,您的查询将获得良好的性能。

            外键可以帮助查询优化器为给定查询获得最佳查询计划。

            外键检查是您更新数据时的一个因素(这是一个单独的考虑因素 - 我在这里假设您关心的是查询 - 除非您通过查询一词暗示两者)。

            【讨论】:

              【解决方案9】:

              外键会减慢插入和更改的速度,因为必须验证每个外键引用。外键要么不影响选择,要么让它更快,这取决于 DBMS 是否使用外键索引。

              外键对删除有复杂的影响。如果您要删除引用外键的内容,则不会影响任何内容,但是如果您要删除的内容被另一行/表中的外键引用,则通常会引起问题。

              外键可能会在表创建和更改时导致轻微的性能下降。

              当然,这一切都假设正在使用外键验证。

              【讨论】:

                【解决方案10】:

                我相信上面提到的帖子指出,在 FK 字段上放置索引可以提高性能,而不仅仅是 FK 关系可以提高性能。表上存在 FK 不会对 SELECT 查询产生任何影响,除非正在执行 JOIN 操作,此时,FK 字段上的 FK 关系 AND 索引将提高性能。

                【讨论】:

                  【解决方案11】:

                  如果您强制执行参照完整性,影响 FK 字段的 INSERT 和 UPDATE 会更慢。但是,通常不必担心,尤其是很多数据库是 80% 读取/20% 写入。这也是一个值得付出的代价。

                  在外键上创建索引通常是有益的,但显然这在很大程度上取决于您正在运行的 SELECT 语句。

                  通常,由于规范化(避免重复数据和同步问题),您需要外键。归一化到 3 度,然后在分析真实世界的性能后,您可以考虑去归一化。

                  【讨论】:

                    猜你喜欢
                    • 2011-01-10
                    • 2011-10-13
                    • 1970-01-01
                    • 2010-10-05
                    • 2013-11-26
                    • 2011-01-11
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-06-17
                    相关资源
                    最近更新 更多