我有一个表有十个外键。如果我在所有十个键上都有索引,那么我将在插入时占多少?

时间:2009-06-23 16:46:24

标签: sql-server indexing

共识似乎是所有外键都需要索引。如果我遵守法律规定,我会在插入物上产生多少开销?

注意:

  1. 假设数据库是一个很好的设计,并且所有连接都是合法的。
  2. 所有主键和外键均为Int。
  3. 类型
  4. 有些表是查找表,少于10条记录,不太可能增大。
  5. 这是一个OLTP数据库。
  6. 一些连接是查找少于10条记录的表。

10 个答案:

答案 0 :(得分:2)

Here是一个很好的列表,列出了何时以及使用何种类型的索引。我不认为你应该接受“法律”并指出一切。您需要定义将在查询连接中使用的内容并相应地进行索引

答案 1 :(得分:2)

由于需要更新所有索引,因此插入会对性能造成严重影响。粗略地说,您将为大表上的插入创建一个磁盘写入,并为表上的每个索引稍微多于一个(平均)。每个索引叶节点都会产生一次写入,并且当叶子和(不太常见)父节点分裂时,会不时发生一些额外的写入。

每个表和索引写入也会产生日志流量。对于批量插入数据,特别严重的惩罚是,因为正在插入批量加载数据的表上的活动索引将更新 每行 - 并且这些更新 没有最低限度的记录。 这将大量炸毁你的I / O(这将是随机访问而不是良好的顺序批量写入),并且还会产生大量的日志流量。

答案 2 :(得分:1)

没有必要在指向具有少量元素的查找表的外键上放置索引。

答案 3 :(得分:1)

回答你问题的唯一可能方法是测试。例如,如果任何键的基数为10,则它们可能不会非常有用。所以你有一些工作要做测试。但它与您的表格大小,密钥大小,绝对活动级别和CRUD元素的组合有很大关系。不信任所有简单的答案。

编辑:

如果您当前没有数据,因为这是初始设计,请仅从明显的索引开始,并根据测试添加其他索引。除非它是一个低变化的数据库,否则将它们全部添加是没有意义的。但如果它是只读的,那就没有多少惩罚。 (您未提供的另一条信息。)

答案 4 :(得分:1)

  

共识似乎是所有外键都需要索引。如果我遵守法律规定,我会在插入物上产生多少开销?

有两个开销:在引用表上的DML和引用表上的DML

引用的表应该有索引,否则您将无法创建FOREIGN KEY

引用表不能有索引。它会使INSERT进入引用表的速度稍慢,并且不会将INSERT影响到引用的表中。

每当您在引用表中插入行时,都会发生以下情况:

  1. 根据此查询中的FOREIGN KEY检查行:

    SELECT  TOP 1 NULL
    FROM    referenced ed
    WHERE   ed.pk = @new_fk_value
    
    • 插入行
    • 行上的索引(如果有)已更新。
  2. 始终执行前两个步骤,并且步骤1通常在引用的表上使用索引(同样,如果没有此索引,则无法创建FOREIGN KEY关系。)

    步骤1FOREIGN KEY特有的唯一开销。

    步骤3的开销仅由索引存在的事实暗示。如果没有FOREIGN KEY,那就完全相同了。

    但是如果你没有在引用表上定义索引,那么来自引用表的UPDATEDELETE会慢得多,特别是如果后者很大的话。

    每当您从引用的表中DELETE时,就会发生以下情况:

    1. 根据此查询中的FOREIGN KEY检查行:

      SELECT  TOP 1 NULL
      FROM    referencing ing
      WHERE   ing.fk = @old_pk_value
      
      • 该行已删除
      • 行上的索引已更新。
    2. 很容易看到此查询最有可能受益于referencing.fk上的索引。

      否则,即使您要删除单个记录来检查约束,优化器也需要在整个表上构建HASH TABLE

答案 5 :(得分:1)

了解影响的唯一方法是测试。答案可能会有很大不同,具体取决于您的系统是否倾向于在批量插入中插入大量数据,或者一次从用户界面插入一条记录。它还很大程度上取决于表的大小和索引的总数。测试是确定您应该使用哪些索引的唯一方法。一般的经验法则是首先索引将在where子句中使用的外键字段和字段。但这就是从哪里开始查看你的系统,而不是“全部都是”的答案。

我会说我观察到用户倾向于更多地容忍花在插入上花费的时间比花在查询系统上花费的时间更长。这一点尤其如此,因为高级管理人员往往比数据输入做更多的查询,他们可能会变得暴躁,并且如果他们觉得自己的时间浪费就有能力做些事。

在新系统中,您需要生成系统在实施时将具有的预期卷的测试记录。如果你不这样做,那么你会发现在同一个测试床上运行正常的查询(和设计)可能很糟糕,真正的用户同时对大型表做多个事情。重构一个没有在设计中考虑和测试性能的数据库是没有意义的。由于开发人员没有针对真实的卷(或者在新项目的情况下,预期的卷数)进行测试,因此撤回生产更改并不是因为查询花费的时间超过了超时设置。

SQL Server具有帮助您确定最佳索引的工具。使用索引向导和执行计划来查看索引的位置。将索引放在字段和测试插入上以查看是否存在负面影响。没有一个正确的答案。它甚至不会在数据库的生命周期内保持相同的答案。

答案 6 :(得分:1)

插入/更新/删除始终命中索引并写入其中。选择有时命中索引以从中读取,具体取决于查询优化程序的分析或最佳猜测。如果您不需要索引来加速读取(例如,如果列只有少量的潜在值),那么就去除它。

如果子表中有十亿行,并且希望删除其中的一百万行,因为您要从父表中删除一行,其中该行是所有1亿子行的父行,那么索引只会降低整个操作的速度,因为系统也必须从索引中删除,但不会加快操作速度,因为系统不会使用索引来加快选择要删除的行。

答案 7 :(得分:0)

这些字段是否会用于搜索和排序?如果是这样,索引可能是个好主意。唯一知道的方法是测试测量并再次测试

编辑:搜索表可能会被缓存,但这对搜索引用表的搜索查询没有帮助。你的数据表是。

答案 8 :(得分:0)

谢谢大家的意见。

根据您的反馈,我想我会为所有外键添加索引,除了指向查找表的那些(包含少量不太可能改变的记录)。这将把所需的外键索引数量减半(从10到5)。

如果有人有进一步的见解,请随时发布新的答案。我还有一些选票。 :)

答案 9 :(得分:0)

我知道性能是一个关键问题。

IMO,您应该考虑OLTP数据没有索引(因此没有FK)的后果。您可能会在此类系统上遇到数据完整性问题。