SQL Server her satır için fonksiyonları bir kez değerlendirir mi?


9

Ben böyle bir sorgu var:

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

Bu, yürütme planında aşağıdakine benzer bir ipucu verir:

Yürütme İpucu

Does dateaddaramaya Yüklem parçası sorgusunda her satır için idam? Yoksa SQL Server, tüm sorgu için değeri bir kez hesaplıyor mu?

Yanıtlar:


13

Çalışma zamanı sabitleri olarak bilinen bazı işlevler, sabit katlama adı verilen işlemden geçer . Bir sabiti 'katlayarak', sorgu yürütme işleminin başlarında değerlendirilir, sonuç önbelleğe alınır ve bunun yerine önbelleğe alınan sonuç gerektiğinde. Sorgunuzdaki ifade DATEADD(dd, 0, DATEDIFF(dd, 0, getdate())), afaik, bir çalışma zamanı sabitidir ve bu nedenle her sorgu için yalnızca bir kez katlanır ve değerlendirilir.

Diğer bilgiler: RAND()kişinin çözülemez olmasını beklediği fonksiyon aslında katlanabilir, bu da beklenmedik davranışlara yol açar. Ancak, örneğin NEWID(), diğerleri katlanabilir değildir ve satır başına bir değerlendirmeyi zorlar.


2
@StuartBlackler - İşte SQL Server'ın nasıl çalıştığını gösteren bir gösteriGETDATE() .
Nick Chammas

2

İcra planları harika ama bazen size gerçeği söylemiyorlar. İşte performans testine dayanan bir kanıt.

(ve sonuçta - ifade her satır için değerlendirilmiyor)


;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 satır etkilendi)

Bu OP sorgusu ve çalışması yaklaşık 12 saniye sürüyor

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

Yürütmeden önce bir parametrede tarihi saklayan bu sorgu yaklaşık 12 saniye sürer.

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

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

Ve sadece sonuçları doğrulamak için -
col1 üzerinde hesaplamayı yapar ve bu nedenle her satır için ifadeyi yeniden hesaplamak zorunda Bu sorgu çalıştırmak için yaklaşık 30 saniye sürer.

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

Tüm sorgular tekrar tekrar aynı metrikleri göstererek yürütüldü

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.