SQL Server valuta le funzioni una volta per ogni riga?


9

Ho una domanda come questa:

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

Ciò fornisce una descrizione del piano di esecuzione simile a questa:

Descrizione comando

La dateaddparte dei predicati di ricerca viene eseguita per ogni riga della query? Oppure SQL Server calcola il valore una volta per l'intera query?

Risposte:


13

Alcune funzioni che sono note per essere costanti di runtime passano attraverso il processo chiamato ripiegamento costante . 'Ripiegando' una costante viene valutata un'espressione all'inizio dell'esecuzione della query, il risultato viene memorizzato nella cache e il risultato memorizzato nella cache invece quando necessario. L'espressione nella tua query DATEADD(dd, 0, DATEDIFF(dd, 0, getdate()))è, a dir poco, una costante di runtime e quindi verrà piegata e valutata una sola volta per query.

Come curiosità: la RAND()funzione che ci si aspetterebbe di essere spiegabile è in realtà pieghevole, il che porta a un comportamento inaspettato. Ma altri, ad esempio NEWID(), non sono pieghevoli e imporranno una valutazione per riga.


2
@StuartBlackler - Ecco una dimostrazione di come funzionano le pieghe di SQL Server GETDATE().
Nick Chammas,

2

I piani di esecuzione sono fantastici, ma a volte non ti dicono la verità. Quindi ecco una prova basata sul test delle prestazioni.

(e la linea di fondo: l'espressione non viene valutata per ogni riga)


;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 righe interessate)

Questa è la query OP e l'esecuzione richiede circa 12 secondi

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

Questa query che memorizza la data in un parametro prima dell'esecuzione richiede circa lo stesso tempo, 12 secondi.

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

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

E solo per verificare i risultati -
Questa query che esegue il calcolo su col1 e quindi deve ricalcolare l'espressione per ogni riga richiede circa 30 secondi per l'esecuzione.

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

Tutte le query sono state eseguite ripetutamente mostrando le stesse metriche

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.