Tôi có một truy vấn chạy trong 800 mili giây trong SQL Server 2012 và mất khoảng 170 giây trong SQL Server 2014 . Tôi nghĩ rằng tôi đã thu hẹp điều này xuống mức ước tính cardinality kém cho Row Count Spool
nhà điều hành. Tôi đã đọc một chút về các toán tử bộ đệm (ví dụ, ở đây và ở đây ), nhưng vẫn gặp khó khăn khi hiểu một số điều:
- Tại sao truy vấn này cần một
Row Count Spool
toán tử? Tôi không nghĩ rằng nó cần thiết cho tính chính xác, vậy nó đang cố gắng cung cấp tối ưu hóa cụ thể nào? - Tại sao SQL Server ước tính rằng phép nối với
Row Count Spool
toán tử loại bỏ tất cả các hàng? - Đây có phải là một lỗi trong SQL Server 2014 không? Nếu vậy, tôi sẽ gửi trong Connect. Nhưng tôi muốn hiểu sâu hơn trước.
Lưu ý: Tôi có thể viết lại truy vấn dưới dạng LEFT JOIN
hoặc thêm chỉ mục vào các bảng để đạt được hiệu suất chấp nhận được trong cả SQL Server 2012 và SQL Server 2014. Vì vậy, câu hỏi này là về cách hiểu sâu hơn về truy vấn cụ thể này và lên kế hoạch làm thế nào để cụm từ truy vấn khác nhau.
Truy vấn chậm
Xem Pastebin này cho một kịch bản thử nghiệm đầy đủ. Đây là truy vấn kiểm tra cụ thể mà tôi đang xem:
-- Prune any existing customers from the set of potential new customers
-- This query is much slower than expected in SQL Server 2014
SELECT *
FROM #potentialNewCustomers -- 10K rows
WHERE cust_nbr NOT IN (
SELECT cust_nbr
FROM #existingCustomers -- 1MM rows
)
SQL Server 2014: Gói truy vấn ước tính
SQL Server tin rằng Left Anti Semi Join
đến Row Count Spool
sẽ lọc 10.000 hàng xuống 1 hàng. Vì lý do này, nó chọn một LOOP JOIN
tham gia tiếp theo #existingCustomers
.
SQL Server 2014: Gói truy vấn thực tế
Như mong đợi (bởi tất cả mọi người trừ SQL Server!), Row Count Spool
Đã không xóa bất kỳ hàng nào. Vì vậy, chúng tôi đang lặp 10.000 lần khi SQL Server dự kiến lặp lại một lần.
SQL Server 2012: Gói truy vấn ước tính
Khi sử dụng SQL Server 2012 (hoặc OPTION (QUERYTRACEON 9481)
trong SQL Server 2014), việc Row Count Spool
không giảm số lượng hàng ước tính và tham gia băm được chọn, dẫn đến một kế hoạch tốt hơn nhiều.
THAM GIA TRẢ LẠI viết lại
Để tham khảo, đây là cách tôi có thể viết lại truy vấn để đạt được hiệu suất tốt trong tất cả SQL Server 2012, 2014 và 2016. Tuy nhiên, tôi vẫn quan tâm đến hành vi cụ thể của truy vấn ở trên và liệu nó có là một lỗi trong Công cụ ước tính Cardinality SQL Server 2014 mới.
-- Re-writing with LEFT JOIN yields much better performance in 2012/2014/2016
SELECT n.*
FROM #potentialNewCustomers n
LEFT JOIN (SELECT 1 AS test, cust_nbr FROM #existingCustomers) c
ON c.cust_nbr = n.cust_nbr
WHERE c.test IS NULL