SQL Server ประเมินฟังก์ชันหนึ่งครั้งสำหรับทุกแถวหรือไม่


9

ฉันมีคำถามเช่นนี้

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

สิ่งนี้จะให้คำแนะนำเครื่องมือในแผนการดำเนินการที่คล้ายกับสิ่งนี้:

เคล็ดลับการดำเนินการ

ที่ไม่dateaddเป็นส่วนหนึ่งของการแสวงหาภาคได้รับการดำเนินการสำหรับแถวในแบบสอบถามทุกครั้งหรือไม่ หรือ SQL Server คำนวณค่าหนึ่งครั้งสำหรับแบบสอบถามทั้งหมดหรือไม่

คำตอบ:


13

ฟังก์ชั่นบางอย่างที่เป็นที่รู้จักเป็นค่าคงที่รันไทม์ไปผ่านกระบวนการที่เรียกว่าการพับอย่างต่อเนื่อง โดย 'fold' ค่าคงที่นิพจน์จะได้รับการประเมินในช่วงต้นของการเรียกใช้คิวรีผลลัพธ์จะถูกแคชและผลลัพธ์แคชแทนเมื่อต้องการ นิพจน์ในแบบสอบถามของคุณ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
;

การค้นหาทั้งหมดจะถูกดำเนินการซ้ำ ๆ โดยแสดงเกี่ยวกับการวัดเดียวกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.