【问题标题】:What should I do to get an Clustered Index Seek instead of Clustered Index Scan?我应该怎么做才能获得聚集索引搜索而不是聚集索引扫描?
【发布时间】:2010-11-24 11:29:14
【问题描述】:

我在 SQL Server 2005 中有一个存储过程,当我运行它并查看它的执行计划时,我注意到它正在执行聚集索引扫描,这花费了 84%。我读到我必须修改一些东西才能在那里获得聚集索引搜索,但我不知道要修改什么。

我将不胜感激。

谢谢,

布赖恩

【问题讨论】:

  • 查询和表架构怎么样?

标签: sql-server-2005 clustered-index


【解决方案1】:

没有任何细节很难猜出问题是什么,甚至根本就没有问题。选择扫描而不是搜索可能受多种因素影响:

  • 查询表示一个覆盖整个表的结果集。 IE。查询是一个简单的SELECT * FROM <table>。这是一个微不足道的情况,可以通过聚集索引扫描完美覆盖,无需考虑其他任何事情。
  • 优化器别无选择:
    • 查询表示整个表的子集,但过滤谓词位于不属于聚集键的列上,并且这些列上也没有非聚集索引。除了全面扫描之外,这些不是替代计划。
    • 查询对聚集索引键中的列有过滤谓词,但它们不是SARGable。过滤谓词通常需要重写以使其成为 SARGable,正确的重写取决于具体情况。由于隐式转换规则,可能会出现更微妙的问题,例如。过滤谓词是WHERE column = @value,但列是VARCHAR(Ascii),@value 是NVARCHAR(Unicode)。
    • 查询对聚集键中的列有 SARGale 过滤谓词,但最左边的列没有被过滤。 IE。聚集索引位于列 (foo, bar) 上,但 WHERE 子句仅位于 bar 上。
  • 优化器选择扫描。
    • 当替代方案是非聚集索引然后扫描(或范围搜索)但选择使用聚集索引时,原因可以通常追踪到index tipping point,因为查询投影缺少非聚集索引覆盖。请注意,这不是您的问题,因为您期望的是聚集索引搜索,而不是非聚集索引搜索(假设问题 100% 准确并记录在案......)
    • 基数估计。查询成本估计基于聚集索引键统计信息,该统计信息提供对结果基数的估计(即匹配多少行)。在一个简单的查询中这不可能发生,因为任何对搜索或范围搜索的估计都将低于扫描的估计,无论统计数据有多差,但是在具有连接的 复杂 查询中和过滤多个表,事情更复杂,计划可能包括预期搜索的扫描,因为查询优化器可能会选择连接评估顺序与观察者期望相反的计划。逆序选择可能是正确的(大多数时候),也可能是有问题的(通常是由于统计数据过时或参数嗅探)。
    • 订购保证。扫描将以保证的顺序生成结果,执行树上较高的元素可能会受益于此顺序(例如,可以消除排序或假脱机,或者可以使用合并连接代替哈希/嵌套连接)。总体而言,由于选择了明显较慢的访问路径,查询成本会更高。

这些是为什么在预期聚集索引搜索时可能会出现聚集索引扫描的一些快速指示。这个问题非常笼统,除了依靠 8 号球外,不可能给出“为什么”的答案。现在,如果我将您的问题正确记录并正确表达,那么期望聚集索引 seek 这意味着您正在搜索基于聚集键值的唯一记录。在这种情况下,问题必须与 WHERE 子句的 SARGability 相关。

【讨论】:

  • “在一个简单的查询中这不可能发生,因为任何对搜索或范围搜索的估计都将低于扫描的估计”......不是真的......如果只有 10% 的行有Special = true (1),那么简单查询Select * From table where Special = 0会一直选择一个表扫描。即使在特殊列上存在索引也是如此,只要该索引不是聚集索引。 (如果索引是聚集索引,那么优化器当然会选择范围查找。)
  • @Charles:但这是我刚刚提到的“指数临界点”。顺便说一句,您的示例查询不是“简单”(即微不足道,请参阅msdn.microsoft.com/en-us/library/aa226174%28SQL.70%29.aspx):“一个 SELECT 语句,其中所有列都在唯一的覆盖索引中,并且没有其他索引包含该组列。 "
  • 如果这就是你所说的“简单”的意思,那么我在技术上可以同意,但在上下文中,如果没有澄清你对“简单”这个词的含义,读者会得到一个非常不同的,不正确,印象。如果您将“简单”一词放在引号中或突出显示,并在括号中或作为脚注定义 yr,那么很好......否则,读者认为任何“简单”查询都不会有这个问题,这是不正确的,因为你提到的原因。 ...为了加剧问题,您将复杂性半定义为与连接复杂性相关的,这与小费问题无关。
【解决方案2】:

如果查询包含表中超过一定百分比的行,优化器将选择进行扫描而不是查找,因为它预测在这种情况下它将需要更少的磁盘 IO(对于查找,它返回的每一行在索引中的每个级别都需要一个磁盘 IO),而对于扫描,整个表中的每行只有一个磁盘 IO。

因此,如果在 b-tree 索引中有 5 个级别,那么如果查询将生成表中超过 20% 的行,则读取整个表比为每个执行 5 个 IO 更便宜20% 的行...

您能否进一步缩小查询的输出范围,以减少流程中此步骤返回的行数?这将有助于它选择搜索而不是扫描。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 2019-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多