SQL Server计划:索引扫描/索引搜索之间的区别

cin*_*ndi 81 sql sql-server sql-execution-plan

在SQL Server执行计划中,索引扫描和索引搜索之间的区别是什么

我在SQL Server 2005上.

Jus*_*tin 118

索引扫描是SQL服务器读取整个索引以查找匹配项的位置 - 这需要的时间与索引的大小成比例.

索引查找是SQL服务器使用索引的b树结构直接查找匹配记录的位置(请参阅http://mattfleming.com/node/192以了解其工作原理) - 所用时间仅与匹配记录的数量.

  • 通常,索引搜索优于索引扫描(当匹配记录的数量远远低于记录总数时),因为执行索引搜索所花费的时间是恒定的,无论您的记录中的记录数量是多少.表.
  • 但请注意,在某些情况下,索引扫描可能比索引搜索更快(有时显着更快) - 通常在表非常小时,或者大部分记录与谓词匹配时.

  • @RonakAgrawal https://web.archive.org/web/20141003135304/http://www.mattfleming.com:80/node/192 (5认同)
  • 链接仍然有效吗?对我来说它不起作用.如果有更新的链接,请提供帮助 (3认同)
  • @RonakAgrawal看起来链接实际上已经死了 - 也许检查一下[维基百科](https://en.wikipedia.org/wiki/B-tree)? (2认同)

Joh*_*som 71

遵循的基本规则是扫描是坏的,寻求是好的.

索引扫描

当SQL Server执行扫描时,它会将要从磁盘读取的对象加载到内存中,然后从上到下读取该对象,查找所需的记录.

索引寻求

当SQL Server执行搜索时,它知道数据将在索引中的哪个位置,因此它从磁盘加载索引,直接转到它需要的索引部分并读取到它所需的数据所在的位置.这显然是一种比扫描更有效的操作,因为SQL已经知道它所寻找的数据所在的位置.


如何修改执行计划以使用Seek而不是Scan?

当SQL Server正在查找您的数据时,可能使SQL Server从搜索切换到扫描的最大问题之一是当您要查找的某些列未包含在您希望它使用的索引中时.大多数情况下,这将使SQL Server回退到执行聚簇索引扫描,因为聚簇索引包含表中的所有列.这是最重要的原因之一(至少在我看来)我们现在能够在索引中包含INCLUDE列,而无需将这些列添加到索引的索引列中.通过在索引中包含其他列,我们增加了索引的大小,但是我们允许SQL Server读取索引,而不必返回聚簇索引,或者自己获取这些值.

参考

有关SQL Server执行计划中每个运算符的详细信息,请参阅....


Kun*_*nge 14

扫描与寻求


索引扫描:

由于扫描触及表中的每一行,无论其是否合格,因此成本与表中的总行数成比例.因此,如果表很小或者大多数行符合谓词的条件,则扫描是一种有效的策略.

索引寻求:

由于搜索仅触及限定行和包含这些限定行的页面,因此成本与合格行和页面的数量成比例,而不是与表中的总行数成比例.

索引扫描只是扫描从第一页到最后一页的数据页.如果表上有索引,并且查询触及大量数据,这意味着查询检索的数据超过50%或90%,然后优化器只扫描所有数据页检索数据行.如果没有索引,那么您可能会在执行计划中看到表扫描(索引扫描).

索引搜索通常是高选择性查询的首选.这意味着查询只是请求更少的行数,或只是检索表中行的其他10个(有些文档说15%).

通常,查询优化器尝试使用索引查找,这意味着优化器已找到一个有用的索引来检索记录集.但是,如果由于表上没有索引或没有有用索引而无法执行此操作,则SQL Server必须扫描满足查询条件的所有记录.

扫描与搜索之间的区别?

扫描返回整个表或索引.搜索基于谓词有效地从索引的一个或多个范围返回行.例如,请考虑以下查询:

select OrderDate from Orders where OrderKey = 2
Run Code Online (Sandbox Code Playgroud)

扫描

通过扫描,我们读取orders表中的每一行,评估谓词"WhereKey = 2",如果谓词为真(即,如果行符合条件),则返回该行.在这种情况下,我们将谓词称为"残差"谓词.为了最大限度地提高性能,我们尽可能评估扫描中的残差谓词.但是,如果谓词太昂贵,我们可以在单独的过滤器迭代器中对其进行评估.残差谓词出现在带有WHERE关键字的文本showplan中或带有标记的XML showplan中.

以下是使用扫描的此查询的文本showplan(为了简洁而略微编辑):

| -Table Scan(OBJECT:([ORDERS]),WHERE:([ORDERKEY] =(2)))

下图说明了扫描:

在此输入图像描述

由于扫描触及表中的每一行,无论其是否合格,因此成本与表中的总行数成比例.因此,如果表很小或者大多数行符合谓词的条件,则扫描是一种有效的策略.但是,如果表很大并且大多数行不符合条件,我们会触及更多页面和行,并执行比必要更多的I/O.

寻求

回到这个例子,如果我们在OrderKey上有一个索引,那么搜索可能是一个更好的计划.通过搜索,我们使用索引直接导航到满足谓词的那些行.在这种情况下,我们将谓词称为"搜索"谓词.在大多数情况下,我们不需要将搜索谓词重新评估为残差谓词; 索引确保seek只返回符合条件的行.搜索谓词出现在带有SEEK关键字的文本showplan中或带有标记的XML showplan中.

以下是使用搜索的同一查询的文本showplan:

| -Index Seek(OBJECT:([ORDERS].[OKEY_IDX]),SEEK:([ORDERKEY] =(2))ORDERED FORWARD)

下图说明了寻求:

在此输入图像描述

由于搜索仅触及限定行和包含这些限定行的页面,因此成本与合格行和页面的数量成比例,而不是与表中的总行数成比例.因此,如果我们有一个高度选择性的搜索谓词,那么搜索通常是一种更有效的策略; 也就是说,如果我们有一个搜索谓词可以消除表的很大一部分.

关于showplan的说明

在showplan中,我们区分扫描和搜索以及堆上的扫描(没有索引的对象),聚簇索引和非聚簇索引.下表显示了所有有效组合:

在此输入图像描述

https://blogs.msdn.microsoft.com/craigfr/tag/scans-and-seeks/


Big*_*yes 7

简短回答:

  • 索引扫描:触摸除某些列之外的所有行.

  • 索引搜索:触摸某些行和某些列.