SQL Server có đánh giá các chức năng một lần cho mỗi hàng không?


9

Tôi có một truy vấn như thế này:

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

Điều này đưa ra một chú giải công cụ về kế hoạch thực hiện tương tự như sau:

Tooltip thực thi

Có phải dateaddmột phần của các vị từ tìm kiếm được thực thi cho mỗi hàng trong truy vấn không? Hay SQL Server tính giá trị một lần cho toàn bộ truy vấn?

Câu trả lời:


13

Một số hàm được biết là hằng số thời gian chạy trải qua quá trình gọi là hằng số gấp . Bằng cách 'gấp' một hằng số một biểu thức được đánh giá sớm trong quá trình thực hiện truy vấn, kết quả được lưu vào bộ đệm và kết quả được lưu trong bộ nhớ cache thay vào đó khi cần. Biểu thức trong truy vấn của bạn DATEADD(dd, 0, DATEDIFF(dd, 0, getdate()))là afaik, hằng số thời gian chạy và do đó sẽ được gấp lại và chỉ được đánh giá một lần cho mỗi truy vấn.

Như câu đố: RAND()chức năng mà người ta mong đợi không thể mở được thực sự có thể gập lại được, dẫn đến một số hành vi không mong muốn. Nhưng khác, chẳng hạn NEWID(), không thể gập lại và sẽ buộc đánh giá mỗi hàng.


2
@StuartBlackler - Đây là một minh chứng về cách SQL Server gấp các chức năng như thế nào GETDATE().
Nick Chammas

2

Kế hoạch thực hiện là tuyệt vời nhưng đôi khi họ không nói cho bạn sự thật. Vì vậy, đây là một bằng chứng dựa trên kiểm tra hiệu suất.

(và dòng dưới cùng - biểu thức không được đánh giá cho mỗi hàng)


;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 hàng bị ảnh hưởng)

Đây là truy vấn OP và mất khoảng 12 giây để chạy

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

Truy vấn này lưu trữ ngày trong một tham số trước khi thực hiện, mất khoảng thời gian tương tự, 12 giây.

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

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

Và chỉ để xác minh kết quả -
Truy vấn này thực hiện tính toán trên col1 và do đó phải tính toán lại biểu thức cho mỗi hàng mất khoảng 30 giây để chạy.

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

Tất cả các truy vấn được thực hiện liên tục hiển thị về cùng một số liệu

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.