从索引列上非常大的表中选择SELECT TOP 1非常慢,但不是相反的顺序(“ desc”)


17

我们有一个大型数据库,大约1TB,在功能强大的服务器上运行SQL Server 2014。几年一切正常。大约2周前,我们进行了全面维护,其中包括:安装所有软件更新;重建所有索引和紧凑的数据库文件。但是,我们没想到在实际负载相同的情况下,在某些阶段数据库的CPU使用率会增加100%以上至150%。

经过大量的故障排除后,我们将其范围缩小到一个非常简单的查询,但找不到解决方案。查询非常简单:

select top 1 EventID from EventLog with (nolock) order by EventID

它总是需要约1.5秒!但是,带有“ desc”的类似查询始终大约需要0毫秒:

select top 1 EventID from EventLog with (nolock) order by EventID desc

PTable大约有5亿行;EventIDASC数据类型为bigint(标识列)的主聚集索引列(有序)。有多个线程在顶部的数据表中插入数据(较大的EventID),有1个线程从底部的数据表中删除数据(较小的EventID)。

在SMSS中,我们验证了两个查询始终使用相同的执行计划:

  • 聚集索引扫描;

  • 估计行数和实际行数均为1;

  • 估计的执行次数和实际的执行次数均为1;

  • 估计I / O成本为8500(似乎很高)

  • 如果连续运行,则两者的查询成本都是相同的50%。

我更新了索引统计信息with fullscan,问题仍然存在;我再次重建了索引,问题似乎消失了半天,但又回来了。

我通过以下方式打开了IO统计信息:

set statistics io on

然后连续运行两个查询,发现以下信息:

(对于第一个查询,慢速查询)

表“ PTable”。扫描计数1,逻辑读407670,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

(对于第二个查询,快速查询)

表“ PTable”。扫描计数1,逻辑读4,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

注意逻辑读取的巨大差异。在两种情况下都使用索引。

索引碎片可以解释一下,但是我相信影响很小。问题从未发生过。另一个证明是,如果我运行如下查询:

select * from EventLog with (nolock) where EventID=xxxx   

即使我将xxxx设置为表中最小的EventID,查询也总是快如闪电。

我们检查了,没有锁定/阻塞问题。

注意:我只是试图简化上面的问题。“ PTable”实际上是“ EventLog”;的PIDEventID

我得到了没有NOLOCK提示的相同结果测试。

有人可以帮忙吗?

在此处输入图片说明

在此处输入图片说明

XML中更详细的查询执行计划,如下所示:

https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob

https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ

我认为提供create table语句并不重要。它是一个旧数据库,已经运行了很长时间,直到进行维护为止。我们自己做了很多研究,并将其范围缩小到我的问题中提供的信息。

该表通常是使用EventID列作为主键创建的,该identity列是type 的列bigint。这时候,我想问题出在索引碎片上。重建索引后,问题似乎已经消失了半天。但是为什么它这么快回来...?

Answers:


18

聚集索引扫描显示423,723逻辑读取以返回第一行,耗时1926 ms:

坚果

按索引顺序查找第一行似乎很多。

您的Ghost清理任务很可能正在运行很长时间,或者已经停止。您应该检查ghost_record_count中的聚集索引,sys.dm_db_index_physical_stats并监视随时间的变化。

从索引末尾开始的有序扫描(看到持续的删除活动)必须先扫描大量的幻影记录,然后才能找到要返回的第一行。这解释了额外的逻辑读取。沿着b树向下搜索到索引的最低值将遇到更少的重影记录。

另一个影响性能的因素是,扫描本身负责删除幽灵记录,如Paul Randal 深入了解《存储引擎内部:幽灵清理》中所述

您应检查跟踪标志661(禁用重影清除)是否处于活动状态。

解决方案

如果虚影清理过程已完全停止,则最有效的解决方案通常是重新启动SQL Server实例。您还应该确保SQL Server正在运行最新的累积更新之一。这些年来,有很多鬼清理错误。

在您的特定情况下:

原来,问题是由同一服务器上的另一个测试数据库引起的。该测试数据库已恢复为“数据丢失”,并且已损坏。令人惊讶的是,鬼清除过程显然卡在了该数据库中。一旦我们从SMSS中删除了损坏的数据库,问题就自行解决了(花费了很长时间,可能导致DB锁定了一小会儿)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.