Buộc SQL Server chạy các điều kiện truy vấn như được viết?


13

Tôi đang sử dụng SQL Server 2008 R2 và tôi có truy vấn giả (SP) này:

select ...
from ...
WHERE    @LinkMode IS NULL
     AND (myColumn IN (...very long-running query...))
     ...
     ...

Vấn đề là truy vấn mất nhiều thời gian để thực thi - ngay cả khi tôi thực thi SP với @LinkMode=2.

Như bạn đã nhận thấy, truy vấn chạy dài chỉ nên được thực hiện nếu @LinkMode là null, đây không phải là trường hợp ở đây. Trong trường hợp của tôi @LinkMode = 2!

Tuy nhiên, nếu tôi thay đổi nó thành:

 select ...
    from ...
    WHERE    1=2
         AND (myColumn IN (...very long time exeted query...))
     ...
     ...

SP không chạy nhanh.

Tôi đã nghe nói rằng đôi khi trình tối ưu hóa có thể tối ưu hóa thứ tự của các tiêu chí.

Vì vậy tôi hỏi :

  • Ngay cả khi trình tối ưu hóa chọn một tuyến đường khác, điều gì có thể nhanh hơn việc kiểm tra nếu =null? Ý tôi là, tôi nghĩ rằng việc kiểm tra đó if a==nullnhiều nhanh hơn chạy truy vấn dài khác ...

  • Làm cách nào tôi có thể buộc SQL Server chạy truy vấn như tôi đã viết (cùng thứ tự)?

Câu trả lời:


22

Bạn đang rơi vào cái bẫy " Truy vấn tất cả ", được Gail Shaw giải thích rất rõ ở đây .

Để tóm tắt vấn đề: SQL Server tối ưu hóa chi phí đáng kể của quá trình biên dịch truy vấn bằng cách lưu trữ kế hoạch truy vấn sau khi biên dịch và sau đó kiểm tra bộ đệm cho kế hoạch truy vấn phù hợp trước khi biên dịch sau. "Kết hợp" xảy ra ở đây hoàn toàn là văn bản, vì vậy giá trị thực của một biến sẽ không ảnh hưởng đến điều này.

Điều đó tốt 99% thời gian, nhưng trong một số trường hợp, điều đó thật tệ . Một trường hợp xấu là khi ai đó cố gắng xây dựng mệnh đề WHERE giống như câu lệnh IF ngắn mạch trong C, v.v. Điều này không hoạt động tốt, vì trình biên dịch SQL phải tạo một kế hoạch truy vấn sẽ hoạt động bất kể về các giá trị tham số thực sự là gì và cách duy nhất để xử lý các điều kiện chuyển đổi logic "thông minh" này trong mệnh đề WHERE là tạo một kế hoạch brute-force đơn giản chỉ quét toàn bộ bảng, lọc các hàng khi nó đi , mà không tận dụng bất kỳ chỉ số.

Không đáng ngạc nhiên, điều này làm cho chúng chậm đồng đều, bất kể giá trị tham số / biến là gì.


8

Không có cách nào đảm bảo để buộc máy chủ SQL thực thi các điều kiện mệnh đề của bạn theo một trình tự cụ thể. Trình tối ưu hóa sẽ luôn đánh giá chúng theo thứ tự mà nó thấy phù hợp.

Những gì bạn có thể làm là một cái gì đó như thế này:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END

3

Nếu đó là một tùy chọn, sử dụng câu lệnh IF để thực thi dạng truy vấn thích hợp. Ngoài ra, trong SQL, bạn cho công cụ db biết phải làm gì, không phải làm như thế nào - mọi thứ không được thực hiện từ đầu đến cuối. Có thể khó dự đoán chính xác những gì nó sẽ làm. Bạn có thể biết điều này mặc dù;)


2

SQL động có thể cũng hoạt động, vì trong trường hợp đó, trình tối ưu hóa truy vấn sẽ nhận được các giá trị thực tế trong thời gian chạy (hãy sửa tôi nếu tôi sai, tôi thực sự không chắc chắn nhưng dường như nhớ sử dụng nó cho các tình huống tương tự) . Nhưng tôi cùng với những người khác trong vấn đề này, trong đó một mệnh đề IF / ELSE sẽ phục vụ bạn tốt nhất, vì đó là giải pháp đơn giản và dễ dàng nhất sẽ thực hiện chính xác những gì cần thiết.

Để tham khảo trong tương lai trong trường hợp bạn chưa sử dụng nó, một trang web xấu xí khủng khiếp với ví dụ hoạt động cho SQL động có thể được tìm thấy ở đây, ví dụ: http://sqlusa.com/bestpractices/dynamicsql/


1

Tôi muốn giới thiệu cấu trúc IF / ELSE .. Nếu vì bất kỳ lý do gì không phù hợp với bạn, bạn luôn có thể xem xét sử dụng tùy chọn VỚI RECOMPILE ..


Bạn có thể giải thích rõ hơn về "cấu trúc if / other" có thể trông như thế nào không? : D
jcolebrand

Tôi sẽ đề xuất sử dụng TÙY CHỌN (VỚI RECOMPILE), vì điều đó sẽ tạo ra một kế hoạch lý tưởng mỗi lần - độ trễ biên dịch sẽ thêm chi phí, nhưng tôi nghi ngờ nó sẽ tốt hơn trong trường hợp này.
SqlRyan
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.