帮助简单查询 - 为什么不使用索引?

时间:2010-05-27 18:48:20

标签: sql-server

我有以下查询:

SELECT MAX([LastModifiedTime]) FROM Workflow

Workflow表中有大约400M行。 LastModifiedTime列上有一个索引,如下所示:

CREATE NONCLUSTERED INDEX [IX_Workflow_LastModifiedTime] ON [dbo].[Workflow] 
(
 [LastModifiedTime] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 100)

上述查询需要1.5分钟才能执行。为什么SQL Server不使用上面的索引并只是检索索引中的最后一行来获取最大值?

顺便说一句,此查询的查询计划显示正在对上述索引执行index scan

感谢。

7 个答案:

答案 0 :(得分:3)

神秘是查询优化器的方式......

如果可能的话,我建议你改变这样的查询:

SELECT TOP (1) [LastModifiedTime]
FROM Workflow 
ORDER BY [LastModifiedTime] DESC;

这在语义上是相同的,优化器将不再考虑使用MAX聚合和扫描(显然它现在就是这样)。它可能会考虑在工作台中进行分类,但希望这样的计划的估计成本远远大于反向搜索的成本。

至于为什么优化器选择显然是一个明显不好的计划,通常涉及很多因素,很难从SO帖子中诊断出来。通常,拥有ASC索引并不总是替代缺少DESC索引,并且您的特定列统计信息(分布)可能已经达到查询优化器内部的一些临界点,它决定选择扫描+聚合而不是反向扫描+顶部。

答案 1 :(得分:1)

我有一个具有类似日期时间字段的表(假设这是您的数据类型)和4M行 - 占您自己的1%,但是当我单击“执行”时,相同的查询几乎回来了。我的索引几乎与您的相同:

CREATE NONCLUSTERED INDEX [IX_PartViewTrack_SearchDate] ON [dbo].[PartViewTrack] 

(
[SearchDate] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF,     
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, 
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

执行计划显示索引扫描。

只是为了咧嘴笑 - 删除索引并查看需要多长时间?

答案 2 :(得分:0)

您能否从执行计划中判断出是否正在使用索引?如果没有,表/索引最后分析的时间是什么时候?如果它从未被分析过,那么SQL服务器仍然认为其中只有100行,并且进行表扫描会更快。

答案 3 :(得分:0)

SELECT MAX([LastModifiedTime]) FROM Workflow with(nolock)

这会更快吗?

答案 4 :(得分:0)

一个黑白问题,没有(对我而言)一个明显的答案。这里有一些非常愚蠢的想法,只是为了清理空气。

  • 是桌子吗?如果一个视图,底层 结构可能会妨碍。 (一世 忘了,你能建立一个非聚集的 物化视图的索引?)

  • 有争用吗?如果是其他用户 长期锁定 表,这可能会减慢速度。 此外,非常频繁的更新 可能会把它扔掉。

  • 查询计划显示索引扫描 正在运行。是索引引用 指数? (还有其他索引吗?聚集索引? 可能不是问题,而是喋喋不休 这里的想法。)

  • 您使用架构吗?索引已开启 dbo.Workflow,但查询没有 指定“dbo”。 (就像我说的, 在这里争取创意。)

所有这些听起来都非常蹩脚,但如果没有动手操作,这些问题可能很难搞清楚。

答案 5 :(得分:0)

这是一个远景:我发现Oracle有时需要一个字段,在它使用索引之前不允许空值。 SQL Server中是否有类似的限制?

答案 6 :(得分:0)

首先使用命令

分析索引
DBCC SHOW_STATISTICS (table_name, index_name)

检查您的索引是否覆盖整个表格。如果没有,请尝试使用

更新统计信息
UPDATE STATISTICS table_name