为什么查询中没有使用特定索引?

时间:2011-07-07 19:10:29

标签: sql-server tsql

我有一个名为Workflow的表。它有37M行。 ID列(int)上有一个主键,还有一个附加列。 ID列是索引中的第一列。

如果我执行以下查询,则不使用PK(除非我使用索引提示)

Select Distinct(SubID) From Workflow Where ID >= @LastSeenWorkflowID

如果我改为执行此查询,则使用PK

Select Distinct(SubID) From Workflow Where ID >= 786400000

我怀疑问题是在查询中使用参数值(我必须这样做)。我真的不想使用索引提示。有解决方法吗?

3 个答案:

答案 0 :(得分:3)

请发布执行计划以及确切的表定义,包括所有索引。

当您使用变量时,优化器不知道查询将具有什么选择性,@ LastSeenWorkflowID可能会过滤掉Workflow中除了最后几行之外的所有行,或者它可能包含所有行。生成的计划必须适用于这两种情况。有一个阈值,在该阈值上,聚集索引的范围搜索变得比非聚簇索引上的完全扫描更昂贵,这仅仅是因为聚簇索引更宽(它包括叶级中的每一列),因此具有要迭代的页面要多得多。生成的计划考虑了@LastSeenWorkflowID的未知值,可能在估计聚簇索引查找的成本时超过该阈值,因此它选择扫描非聚集索引。

您可以提供专门针对此查询的窄索引:

CREATE INDEX WorkflowSubId ON Workflow(ID, SubId);

或:

CREATE INDEX WorkflowSubId ON Workflow(ID) INCLUDE (SubId);

无论@LastSeenWorkflowID的值如何,这样的索引对于您的查询来说太好了。

答案 1 :(得分:2)

假设你的PK是一个身份或者总是大于0,也许你可以试试这个:

Select Distinct(SubID) 
From Workflow 
Where ID >= @LastSeenWorkflowID
    And ID > 0

通过添加第二个条件,可能会导致优化器使用索引查找。

答案 2 :(得分:0)

这是产生次优计划的局部变量的典型例子。

您应该使用OPTION(RECOMPILE)以使用ID的实际参数值编译您的查询。

有关详细信息,请参阅我的博文: http://www.sqlbadpractices.com/using-local-variables-in-t-sql-queries/