(Câu hỏi được chuyển từ SO)
Tôi có một bảng (dữ liệu giả) với chỉ mục được nhóm chứa 2 cột:
Bây giờ tôi chạy hai truy vấn đó:
declare
@productid int =1 ,
@priceid int = 1
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid OR @productid IS NULL)
AND (priceid = @priceid OR @priceid IS NULL)
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid)
AND (priceid = @priceid)
Kế hoạch thực hiện thực tế cho cả hai truy vấn là:
Như bạn có thể thấy, cái đầu tiên đang sử dụng SCAN trong khi cái thứ hai đang sử dụng XEMK.
Tuy nhiên - thêm OPTION (RECOMPILE)
vào truy vấn đầu tiên, thực hiện kế hoạch thực hiện cũng để sử dụng XEMK:
Bạn bè tại DBA chat nói với tôi rằng:
Trong truy vấn của bạn, @ sản phẩm = 1, có nghĩa là (sản phẩmID = @ sản phẩm HOẶC @productID IS NULL) có thể được đơn giản hóa thành (sản phẩmID = @ sản phẩm). Cái trước yêu cầu quét để làm việc với bất kỳ giá trị nào của @productID, cái sau có thể sử dụng tìm kiếm. Vì vậy, khi bạn sử dụng RECOMPILE, SQL Server sẽ xem xét giá trị bạn thực sự có trong @productID và đưa ra kế hoạch tốt nhất cho nó. Với giá trị không null trong @productID, tìm kiếm là tốt nhất. Nếu giá trị của @productID không xác định, gói phải phù hợp với bất kỳ giá trị nào có thể có trong @productID, sẽ yêu cầu quét. Được cảnh báo: TÙY CHỌN (RECOMPILE) sẽ buộc biên dịch lại kế hoạch mỗi khi bạn chạy nó, điều này sẽ thêm một vài mili giây cho mỗi lần thực hiện. Mặc dù đây chỉ là một vấn đề nếu truy vấn chạy rất thường xuyên.
Cũng thế :
Nếu @productID là null, bạn sẽ tìm kiếm giá trị nào? Trả lời: không có gì để tìm kiếm. Tất cả các giá trị đủ điều kiện.
Tôi hiểu rằng OPTION (RECOMPILE)
buộc SQL Server phải xem các giá trị thực tế của các tham số là gì và xem liệu nó có thể TÌM KIẾM với nó không.
Nhưng bây giờ tôi mất lợi ích của việc biên soạn trước.
Câu hỏi
IMHO - SCAN sẽ chỉ xảy ra nếu một param là null.
Điều đó tốt - hãy để SQL SERVER tạo một kế hoạch thực hiện cho SCAN.
NHƯNG nếu SQL Server thấy rằng tôi chạy truy vấn này nhiều lần với các giá trị: 1,1
vậy thì tại sao nó không tạo ra kế hoạch thực hiện KHÁC và sử dụng XEMK cho điều đó?
AFAIK - SQL tạo kế hoạch thực hiện cho các truy vấn thành công nhất .
Tại sao SQL SERVER không lưu kế hoạch thực hiện cho:
@productid int =1 , @priceid int = 1
(Tôi chạy nó nhiều lần với các giá trị đó)
- Có thể buộc SQL giữ kế hoạch thực hiện đó (sử dụng XEMK) - cho lệnh gọi trong tương lai không?