我有以下查询:
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
。
感谢。
答案 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