Dav*_*idN 33 sql-server sql-server-2012
在 MS SQL Server 2012 中运行以下查询时,第二个查询失败,但第一个查询失败。此外,在没有 where 子句的情况下运行时,两个查询都将失败。我不知道为什么两者都会失败,因为两者都应该有空的结果集。任何帮助/见解表示赞赏。
create table #temp
(id int primary key)
create table #temp2
(id int)
select 1/0
from #temp
where id = 1
select 1/0
from #temp2
where id = 1
Run Code Online (Sandbox Code Playgroud)
Pau*_*ite 41
对执行计划的初步查看表明该表达式1/0
是在 Compute Scalar 运算符中定义的:
现在,即使执行计划就开始在最左边的执行,反复呼吁Open
和GetRow
对儿童的迭代方法返回的结果,SQL Server 2005和更高版本中包含借此表达往往只优化定义由计算标量,以推迟到后续评估操作需要结果:
在这种情况下,只有在组装行返回给客户端时才需要表达式结果(您可以认为发生在绿色SELECT
图标处)。按照这种逻辑,延迟评估意味着永远不会评估表达式,因为这两个计划都不会生成返回行。稍微说明一下,Clustered Index Seek 和 Table Scan 都不会返回一行,因此没有要组装返回给客户端的行。
然而,有一个单独的优化,其中一些表达式可以被识别为运行时常量,因此在查询执行开始之前评估一次。
在这种情况下*,可以在 showplan XML 中找到已发生的指示(左侧的聚集索引查找计划,右侧的表扫描计划):
我在这篇博文中写了更多关于底层机制以及它们如何影响性能的文章。使用那里提供的信息,我们可以修改第一个查询,以便在执行开始之前评估和缓存两个表达式:
select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1
select 1/0
from #temp2
where id = 1
Run Code Online (Sandbox Code Playgroud)
现在,第一个计划还包含一个常量表达式引用,并且两个查询都会产生错误消息。第一个查询的 XML 包含:
更多信息:计算标量、表达式和性能
由于运行时常量缓存而报告错误的示例,但执行计划中没有指示(图形或 XML):
SELECT TOP (1) id
FROM #temp2
WHERE id = 1
ORDER BY 1/0;
Run Code Online (Sandbox Code Playgroud)
Gor*_*off 22
我会聪明地猜测(并且在这个过程中可能会吸引一个 SQL Server 专家,他可能会给出一个非常详细的答案)。
第一个查询接近执行:
它选择这条路径是因为您where
在主键上有一个子句。它永远不会进入第二步,因此查询不会失败。
第二个没有主键可以运行,所以它接近查询:
这些值之一1/0
导致了问题。
这是 SQL Server 优化查询的示例。在大多数情况下,这是一件好事。SQL Server 将把条件从select
转移到表扫描操作中。这通常会节省查询评估中的步骤。
但是,这种优化并不是一件绝对的好事。事实上,它似乎违反了 SQL Server文档本身,该文档说该where
子句在select
. 好吧,他们可能对这意味着什么有一些博学的解释。但是,对于大多数人来说,在逻辑上处理where
beforeselect
将意味着(除其他外)“不要select
在未返回给用户的行上生成-clause 错误”。
归档时间: |
|
查看次数: |
7031 次 |
最近记录: |