SQL Server是否为每一行评估一次功能?


9

我有这样的查询:

SELECT col1
FROM   MyTable
WHERE  
    DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())) 
       BETWEEN col2 
       AND     col3
;

这为执行计划提供了类似于以下内容的工具提示:

执行工具提示

dateadd搜索谓词部分是否针对查询中的每一行执行?还是SQL Server为整个查询一次计算值?

Answers:


13

某些已知为运行时常量的函数会经历称为常量折叠的过程。通过“折叠”常量,可以在查询执行的早期对表达式进行求值,将结果缓存,并在需要时缓存结果。查询中的表达式DATEADD(dd, 0, DATEDIFF(dd, 0, getdate()))是afaik,是一个运行时常量,因此每个查询将仅折叠和评估一次。

琐事:RAND()人们期望可以展开的功能实际上是可折叠的,这会导致一些意外的行为。但是其他示例(例如NEWID())是不可折叠的,将强制每行执行一次求值。


2
@StuartBlackler- 这是 SQL Server如何折叠功能的示例GETDATE()
Nick Chammas

2

执行计划很棒,但有时它们只是不告诉你真相。因此,这是基于性能测试的证明。

(最重要的是-表达式未针对每一行进行求值)


;with t(i) as (select 0 union all select i+1 from t where i < 9)
select getdate()-1 as col1,getdate() as col2,getdate() as col3 
into #t 
from t t0,t t1,t t2,t t3,t t4,t t5,t t6,t t7

(受影响的100000000行)

这是OP查询,大约需要12秒钟才能运行

SELECT col1
FROM   #t
WHERE  
    DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())) 
       BETWEEN col2 
       AND     col3
;

此查询在执行之前将日期存储在参数中,大约需要12秒钟的时间。

declare @dt datetime = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())) 

SELECT col1
FROM   #t
WHERE  
      @dt
       BETWEEN col2 
       AND     col3
;

只是为了验证结果-
此查询对col1进行计算,因此必须重新计算每一行的表达式,大约需要30秒钟才能运行。

SELECT col1
FROM   #t
WHERE  
    DATEADD(dd, 0, DATEDIFF(dd, 0, col1)) 
       BETWEEN col2 
       AND     col3
;

重复执行所有查询,显示大约相同的指标

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.