为什么在SQL Server 2012中查询结果为空的错误?


31

在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

Answers:


39

初步查看执行计划,可以发现该表达式1/0是在Compute Scalar运算符中定义的:

图形计划

现在,即使执行计划就开始在最左边的执行,反复呼吁OpenGetRow对儿童的迭代方法返回的结果,SQL Server 2005和更高版本中包含借此表达往往只优化定义由计算标量,以推迟到后续评估操作需要结果

由SET STATISTICS XML生成的Showplans中显示的计算标量运算符可能不包含RunTimeInformation元素。 在图形显示计划中,当在SQL Server Management Studio中选择“包括实际执行计划”选项时,“属性”窗口中可能没有“实际行”,“实际重新绑定”和“实际倒带”。 发生这种情况时,这意味着尽管在编译的查询计划中使用了这些运算符,但它们的工作却由运行时查询计划中的其他运算符执行。 还要注意,SET STATISTICS PROFILE生成的Showplan输出中的执行次数等于SET STATISTICS XML生成的Showplan中重新绑定和倒带的总和。 来自:MSDN联机丛书

在这种情况下,表达式 仅当组装要返回给客户的行时才需要结果(您可以认为这发生在绿色SELECT图标上)。按照这种逻辑,延迟求值将意味着永远不会对表达式求值,因为两个计划都不会生成返回行。稍微花点时间,聚簇索引查找和表扫描都不会返回一行,因此没有要汇编的行可以返回给客户端。

但是,有一个单独的优化,可以将某些表达式标识为运行时常量,在查询执行开始之前对其进行一次评估。在这种情况下,可以在showplan XML(左侧的“聚集索引查找”计划,右侧的“表扫描”计划)中找到已发生的指示:

Showplan XML

在此博客文章中写了更多有关底层机制以及它们如何影响性能的文章。。使用此处提供的信息,我们可以修改第一个查询,以便在执行开始之前对两个表达式进行求值和缓存:

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

现在,第一个计划还包含一个常量表达式引用,并且两个查询都生成错误消息。第一个查询的XML包含:

常数表达

详细信息:计算标量,表达式和性能


21

我将明智地猜测(并且在此过程中可能会吸引SQL Server专家,他可能会给出非常详细的答案)。

第一个查询的执行方式如下:

  1. 扫描主键索引
  2. 在查询所需的数据表中查找值

它选择此路径是因为您where在主键上有一个子句。它永远不会进入第二步,因此查询不会失败。

第二个没有主键可运行,因此它以如下方式处理查询:

  1. 对数据进行全表扫描并检索必要的值

这些值之一1/0导致了问题。

这是SQL Server优化查询的示例。在大多数情况下,这是一件好事。SQL Server将条件从select移到表扫描操作中。这通常可以节省查询评估的步骤。

但是,这种优化并不是一件好事。实际上,这似乎违反了SQL Server 文档本身,该文档指出该where子句在之前进行评估select。好吧,他们可能对此有一些博学的解释。但是,对于大多数人而言,逻辑上处理wherebefore select意味着(除其他事项外)“不会select在未返回给用户的行上产生子句错误”。


1
如果您是对的话,+ 1毫无头绪,但是鉴于唯一的区别是主键,我可以看到最佳答案。

1
@GordonLinoff保罗·兰德尔(Paul Randal)刚刚在Twitter上确认您的回覆不胜枚举。
SchmitzIT 2014年

4
@Still,实际的执行顺序(无论如何)不应导致类似的错误消息。
ypercubeᵀᴹ

7
@ypercube Erland Sommarskog会同意你的观点(连接项)
Paul White说GoFundMonica

2
谢谢您的指点-我已登录并支持该请求。
Gordon Linoff 2014年
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.