SQL Server索引成本

yel*_*ar 8 sql-server indexing performance

我已经读过在SQL Server中添加表索引的权衡之一是插入/更新/删除查询的成本增加,有利于选择查询的性能.

我可以在概念上理解在插入的情况下会发生什么,因为SQL Server必须在与新行匹配的每个索引中写入条目,但更新和删除对我来说更加模糊,因为我无法完全理解数据库引擎必须要做的.

我们以DELETE为例,假设我有以下模式(请原谅伪SQL)

TABLE Foo
 col1 int
,col2 int
,col3 int
,col4 int
PRIMARY KEY (col1,col2)

INDEX IX_1
col3
INCLUDE 
col4
Run Code Online (Sandbox Code Playgroud)

现在,如果我发表声明

DELETE FROM Foo WHERE col1=12 AND col2 > 34
Run Code Online (Sandbox Code Playgroud)

我理解引擎必须做什么才能更新表(如果你愿意,还可以使用聚簇索引).设置索引是为了便于查找要删除的行范围并执行此操作.

但是,此时它还需要更新IX_1并且我给它的查询没有给数据库引擎找到要更新的行的明显有效方法.是否被迫在此时进行完整的索引扫描?引擎是否首先从聚簇索引中读取行并对索引生成更智能的内部删除?

如果我更好地了解幕后发生的事情,我可以帮助我解决这个问题,但我想我的真正问题是这个.我有一个数据库,它花了很多时间在删除,我试图弄清楚我能做些什么.

当我显示删除的执行计划时,它只显示表Foo上的"Clustered Index Delete"条目,该条目在详细信息部分列出了需要更新的其他索引,但我没有得到相关成本的任何指示这些其他指数.

在这种情况下它们都是平等的吗?有什么方法可以估算去除一个或多个这些指数的影响,而无需实际尝试?

And*_*ass 3

非聚集索引还存储聚集键
它不必进行全面扫描,因为:

  • 您的查询将使用聚集索引来定位行
  • 行包含其他索引值 (c3)
  • 使用另一个索引值(c3)聚集索引值(c1,c2),它可以在另一个索引中找到匹配的条目。

(注意:我在解释文档时遇到了麻烦,但我想你的情况下的 IX_1 可以被定义为好像它也在 c1,c2 上排序。由于这些已经存储在索引中,所以使用它们是非常有意义的以更有效地定位记录,例如更新和删除。)

然而,这一切都是有代价的。对于每个匹配行:

  • 它必须读取该行,找出 c3 的值
  • 它必须在非聚集索引中找到 (c3,c1,c2) 的条目
  • 它也必须从那里删除该条目。

此外,虽然范围查询在您的情况下对聚集索引可能很有效(找到匹配项后进行线性访问),但对其他索引的维护很可能会导致 每个匹配行对它们进行随机访问。随机访问的成本比仅从给定匹配开始枚举B+ 树叶节点的成本要高得多。 对于上面的查询,更多的时间花费在非聚集索引维护上——时间量在很大程度上取决于谓词选择的记录数量。
col1 = 12 AND col2 > 34

我的猜测是,成本在概念上是相同的,就像您没有二级索引但有一个单独的表,将 (c3,c1,c2) 作为聚集键中的唯一列,并且您为DELETE每个匹配行执行了 a使用(c3,c1,c2)。显然,索引维护是 SQL Server 内部的,并且速度更快,但从概念上讲,我想上面的内容很接近。

上述情况意味着索引的维护成本将非常接近,因为每个二级索引中的条目数相同(记录数),并且只能在每个索引上逐一进行删除。

如果您需要索引,从性能角度来看,根据已删除记录的数量,您可能最好安排删除,在删除之前删除索引(删除期间未使用的索引),然后将它们添加回来。根据受影响的记录数量,重建索引可能会更快