Чи оцінює SQL Server один раз функції для кожного ряду?


9

У мене такий запит:

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

Це дає підказку щодо плану виконання, подібного до цього:

Підказка про виконання

Чи dateaddвиконується частина предикатів пошуку для кожного рядка запиту? Або SQL Server обчислює значення один раз для всього запиту?

Відповіді:


13

Окремі функції, які, як відомо, є константами виконання, проходять через процес, який називається постійним складанням . За допомогою "складання" константа вираження оцінюється на початку виконання запиту, результат кешується і кешований результат замість цього, коли це потрібно. Вираз у вашому запиті DATEADD(dd, 0, DATEDIFF(dd, 0, getdate()))є, afaik, константа часу виконання, і таким чином буде складено та оцінено лише один раз за запитом.

Як дрібниці: RAND()функція, яку можна було б очікувати, що її неможливо скласти, насправді є складною, що призводить до деякої несподіваної поведінки. Але інші, наприклад NEWID(), не складаються і вимагають оцінки за ряд.


2
@StuartBlackler - Ось демонстрація того, як подібні складові SQL Server GETDATE().
Нік Чаммас

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 рядків)

Це ОР-запит, і для його виконання потрібно близько 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
;

Усі запити виконувались неодноразово, показуючи приблизно однакові показники

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.