我在 4 个 vCPU 虚拟机上运行 Microsoft SQL Server 2016 SP2-CU6 (13.0.5292.0)并max degree of parallelism
设置为.2
cost threshold for parallelism
50
早上,当尝试显示SELECT TOP 100 查询的估计执行计划时,我遇到了大量等待,呈现估计计划的操作需要几分钟,通常在 5 到 7 分钟范围内。同样,这不是查询的实际执行,这只是显示Estimated Execution Plan的过程。
sp_WhoIsActive
将显示PAGEIOLATCH_SH
等待或LATCH_EX [ACCESS_METHODS_DATASET_PARENT]
等待,当我在操作期间运行Paul Randal 的 WaitingTasks.sql脚本时,它显示CXPACKET
等待,工作线程显示PAGEIOLATCH_SH
等待:
*资源描述字段=exchangeEvent id=Port5f6069e600 WaitType=e_waitPortOpen waiterType=Coordinator nodeId=1 tid=0 ownerActivity=notYetOpened waiterActivity=waitForAllOwnersToOpen
工作线程看起来将整个stats
表带入内存(因为这些页码以及从 Paul Randal 的查询中显示的后续页码指向stats
表的聚集键)。一旦计划确实回来了,它在一天的剩余时间里基本上是即时的,即使在我看到stats
缓存中的大部分表磨损只剩下各种记录之后(我假设这些记录是由于来自类似查询的查找操作而被提取的)。
如果查询实际上是使用使用 SCAN 运算符的计划执行的,我会期望这种初始行为,但是为什么在评估执行计划时这样做只是为了到达 SEEK 运算符,如上面链接的计划中所示?我可以做什么(除了在办公时间之前运行此语句以便我的数据被适当缓存)来帮助提高这里的性能?我假设一对覆盖索引会是有益的,但它们真的能保证行为的任何变化吗?我必须在此处的一些存储和维护窗口限制范围内工作,并且查询本身是从供应商解决方案生成的,因此此时欢迎任何其他建议(除了更好的索引)。
您对实际执行计划的请求似乎触发了统计更新。既然你提到这发生在早上,我想有一个通宵的过程会对所涉及的表进行大量修改?
因此 SQL Server 使用统计信息来创建计划,达到修改阈值,并作为操作的一部分执行自动统计信息更新。
在您共享的估计计划的 XML 中,我看到了这些从今天早上开始的统计数据更新日期:
如果这些是非常大的、繁忙的表(似乎可能基于采样百分比),那么统计数据更新占用大量马力也就不足为奇了。
当我在 SSMS 中看到较长的预计计划时间时,它是以下之一(按可能性顺序):
对于您的情况,答案几乎可以肯定是 SQL Server 正在更新或创建统计信息。有几点线索:查询计划的规模小,查询计划相对简单,成本低,编译CPU明显低于编译时间:
新贡献者Josh Darnell还指出了一个很好的线索,即 XML 中统计数据的最后更新时间。
SQL Server 2019 引入了一种新的等待类型WAIT_ON_SYNC_STATISTICS_REFRESH,用于查询等待统计信息更新时的情况。在该版本上诊断此问题要容易得多。在那之前,您只需要依靠间接技术。
解决方法包括在维护期间更新统计信息或为数据库启用 Auto Update Stats Async。请在更改之前了解该选项的全部后果。查询计划将在统计信息更新之前而不是在统计信息更新之后创建。对于某些可能是巨大的胜利的工作负载。对于其他人来说,它弊大于利。