添加“前 20 个”会大大减慢查询速度!

Tra*_*mes 1 sql-server execution-plan sql-server-2016 top table-spool

我有一个疑问:

select * from Aview where field=20
order by id desc
Run Code Online (Sandbox Code Playgroud)

这将在大约 1 秒内从视图中返回 2700 行。

在查询中添加“top 20”使 MSSQL 在 43 秒内返回!

这是一个很难重现的问题,重建统计数据可以修复该问题几天,但随后又回来了。

我使用 SQL 已经有几十年了,我从未见过添加“top”导致时间增加的情况。

查看执行计划,如果执行前 20 条,它似乎正在执行 9.6 亿行的惰性假脱机操作,但如果不执行,则不会执行。

Pau*_*ite 5

这个问题的细节很少,但有足够的内容来尝试回答。

我使用 SQL 已经有几十年了,我从未见过添加“top”导致时间增加的情况。

这比人们想象的更常见。使用TOP引入了“行目标”,因此优化器尝试找到针对几行而不是完整的潜在结果集进行优化的计划。

当估计和其他建模假设正确时,这是一个很好且有用的优化,但否则可能会出错。OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL'))对于这些类型的情况存在查询提示。

请参阅问答TOP 如何(以及为何)影响执行计划?更多细节。

查看执行计划,如果执行前 20 条,它似乎正在执行 9.6 亿行的惰性假脱机操作,但如果不执行,则不会执行。

这可能是一个“性能假脱机”,它针对重复的内侧子结果进行优化。有关更多详细信息,请参阅我的文章嵌套循环连接和性能线轴。请注意,这种类型的线轴不同于常用于万圣节保护的Eager Spool

同样,性能线轴旨在带来好处。当它们不这样做时,可以使用以下方法消除性能假脱机OPTION (NO_PERFORMANCE_SPOOL)查询提示消除性能假脱机。与所有提示一样,这些是高级调整选项,只能在专家分析后使用。

您注意到:

将查询更改为“order by CreatedDate desc”将表假脱机从 960M 行更改为 10K 并解决了问题(但导致了相同的数据),至少现在是“修复”

对于您的特定情况,这可能是一种解决方法,但在理想的情况下,您会确定根本原因。恐怕查询执行和调优问题可能是一件复杂的事情。