SQL Server里书签查找的性能伤害

在个人博客上,之前我常常谈到SQL Serverl里的书签查找,还有它们带来的不少问题。在今天的文章里,我想从性能角度进一步谈下书签查找,还有它们如何拉低你整个SQL Server性能。html

书签查找——反复循环

若是你的非汇集索引不是个覆盖非汇集索引,SQL Server的查询优化器会引入书签查找。对于从非汇集索引你返回的每一行,SQL Server须要在汇集索引里或堆表里进行额外的查找操做。sql

例如当你的的汇集索引包含3层,为了返回必要的信息,对于每一行,你须要3页额外的读取。所以,查询优化器再执行计划里选择书签查找操做,仅在有意义的时候发生——基于你查询的选择度。下图展现了有书签查找操做的执行计划。缓存

一般人们不会太关注书签查找,由于它们只执行几回。若是你的查询选择度过低,查询优化器会用汇集索引扫描或表扫描运算符直接扫描整个表。但只在SQL Server重用缓存的执行计划,这个计划是有屡次不一样运行值,包含书签查找的(基于最初提供的输入值),所以这个状况很容易发生,书签查找反复执行。
工具

为了演示这个性能问题,接下来的查询我指定查询优化器使用特定的非汇集索引。查询自己返回80000行,由于对于每一个查询执行,SQL Server须要进行书签查找80000次——反复执行。 性能

CREATE PROCEDURE RetrieveData
AS
    SELECT * FROM Table1 WITH (INDEX(idxTable1_Column2))
    WHERE Column3 = 2
GO

下图展现了查询执行后的实际执行计划。测试

执行计划看起来很是恐怖(查询优化器甚至启用了并行计划!),由于书签查找运算符这里执行了80000次,查询自己产生了超过165000个逻辑读!(逻辑读个数能够从STATISTIC IO里获取)。优化

接下来向你展现下,当你有不少并行用户执行这个糟糕查询时,SQL Server会发生什么。我会使用ostress.exe(RML工具的一部分)来模拟100个并行用户的查询。spa

ostress.exe -Q”EXEC BookmarkLookupsPerformance.dbo.RetrieveData” -n100 -q

在个人测试系统上花费了近15秒来完成100个并行查询。在此期间,CPU占用很高,由于SQL Server须要嵌套循环运算符来进行书签查找操做。嵌套循环操做固然很占CPU资源。设计

如今让咱们修改索引设计,为这个查询建立覆盖非汇集索引。有了非汇集索引,查询优化器不须要再执行计划里进行书签查找。一个非汇集索引查找就能够返回一样的结果:code

CREATE NONCLUSTERED INDEX idxTable1_Column2 ON Table1(Column3)
INCLUDE (Column2)
WITH (DROP_EXISTING = ON)
GO

此次当咱们再次用ostress.exe执行同个查询,咱们看到每一个查询在5秒内完成。和咱们刚才看到的15秒有很大的区别。这就是覆盖非汇集索引的威力:在咱们查询里气门请求的数据均可以在非汇集索引里直接找到,所以书签查找就能够避免。

小结

在这个文章里我向你展现了很差的书签查找会伤及性能。所以,对于重要的查询快速完成查询很是重要——而使用并行的书签查找的执行计划并非好的选择。这里覆盖非汇集索引能够帮到你。下次设计索引时能够考虑下这个方法。

感谢关注!

原文连接:

https://www.sqlpassion.at/archive/2017/03/13/the-performance-penalty-of-bookmark-lookups-in-sql-server/

相关文章
相关标签/搜索