我有一个名为Workflow的表。它有37M行。 ID列(int)上有一个主键,还有一个附加列。 ID列是索引中的第一列。
如果我执行以下查询,则不使用PK(除非我使用索引提示)
Select Distinct(SubID) From Workflow Where ID >= @LastSeenWorkflowID
如果我改为执行此查询,则使用PK
Select Distinct(SubID) From Workflow Where ID >= 786400000
我怀疑问题是在查询中使用参数值(我必须这样做)。我真的不想使用索引提示。有解决方法吗?
答案 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/