Answers:
与往常一样(大多数情况下),答案在于执行计划。
某些运算符要求所有行都可以到达它们,然后才能开始处理这些行并将它们传递到下游,例如:
因此,它们要么被称为阻塞操作,要么被称为走走停停的运算符,当优化器认为必须处理大量数据才能找到您的数据时,通常会选择它们。
还有其他运算符可以开始流式处理,或立即传递所有找到的行
当查询立即开始返回数据,但又没有立即完成时,通常表明优化器选择了使用启动成本较低的运算符快速定位并返回某些行的计划。
发生这种情况的原因可能是您或优化器引入了行目标。
如果出于某种原因(缺少SARGability,参数嗅探,统计信息不足等)而选择了错误的计划,也会发生这种情况,但这需要更多的挖掘工作才能弄清楚。
保罗·怀特(Paul White)在这里,这里,这里和这里关于连续目标的系列。
还应该注意的是,如果您在谈论SSMS,则只有在整个缓冲区被填满后才出现行,而不仅仅是故意的。
如果我了解您的观察,这就是Management Studio 呈现行的方式,与SQL Server 返回行的方式无关。实际上,通常当您将较大的结果返回给SSMS并尝试在网格中呈现它们时,SSMS无法跟上,并且SQL Server最终等待应用程序处理更多行。在这种情况下,您将看到SQL Server累积ASYNC_NETWORK_IO
等待。
您可以通过使用“结果到文本”而不是“结果到网格”来进行某种程度的控制,因为SSMS绘制文本的速度比绘制网格更快,但是您可能会发现,这可能会影响可读性,具体取决于列数和所涉及的数据类型。当SSMS决定将结果实际写到该窗格时,这两者都会受到影响,这取决于输出缓冲区的容量。
如果有多个语句,并且要强制缓冲区将输出结果呈现到消息窗格,则可以在语句之间使用一些打印技巧:
RAISERROR('', 0, 1) WITH NOWAIT;
但是,当您试图让SSMS在所有输出均来自单个语句时更快地渲染行时,这将无济于事。
更直接地,您可以通过限制要在SSMS中呈现的结果数来控制它。我经常看到人们抱怨将一百万行返回到网格需要多长时间。到底谁会在SSMS网格中处理一百万行呢,我不知道。
有一些类似的hack OPTION (FAST 100)
,它们会优化以检索前100行(或如果没有outer的话则是任何100行ORDER BY
),但是这样做的代价是检索其余行的速度要慢得多,而计划则更多整体上效率低下,所以恕我直言,这并不是一个不错的选择。
您的问题不是关于SQLServer本身,而是:
有办法控制吗?
简短答案:
sqlcmd
代替ssms
或sqlcmd
-mode ofssms
长答案:
当然!但不是一个 -概率
sqlcmd
中使用sqlcmd
-mode 或以-mode 执行查询。spid
然后您将获得会话设置的完整列表。与sqlcmd
会话设置进行比较。如果没有点击-将所有会话设置从事件探查器复制到查询脚本中,以sqlcmd
-mode 执行并逐步切换设置,您将发现罪魁祸首。祝好运!
要添加到sp_BlitzErik的答案中,请使用NOT IN ()
带有sub选择的示例。为了确定某个项目是否在嵌套查询的结果中,(通常)有必要检索整个结果。
因此,我发现提高此类查询性能的一种简便方法是将其重写为LEFT OUTER JOIN
with的条件为RIGHT
null的条件(当然,您可以翻转它,但是谁使用RIGHT OUTER JOINS
?)。这样可以使结果立即开始返回。
WHERE t.x IN (<complex SELECT subquery>)
,即等效的LEFT JOIN LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL
,,那么子查询也必须进行求值(因此,与NOT相同的复杂计划IN版本)。
NOT EXISTS
但Oracle NOT IN
在查询中。但是今天,它必须被视为计划生成器中的错误