Tôi luôn mặc định là NOT EXISTS
.
Các kế hoạch thực thi có thể giống nhau tại thời điểm này nhưng nếu một trong hai cột được thay đổi trong tương lai để cho phép NULL
là NOT IN
phiên bản sẽ cần thực hiện nhiều công việc hơn (ngay cả khi không có NULL
s thực sự hiện diện trong dữ liệu) và ngữ nghĩa của NOT IN
if NULL
s are Dù sao thì hiện tại cũng không phải là thứ bạn muốn.
Khi cả Products.ProductID
hoặc [Order Details].ProductID
cho phép NULL
là NOT IN
sẽ được xử lý giống hệt với truy vấn sau.
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
Kế hoạch chính xác có thể khác nhau nhưng đối với dữ liệu ví dụ của tôi, tôi nhận được như sau.
Một quan niệm sai lầm phổ biến hợp lý dường như là các truy vấn con có tương quan luôn "xấu" so với các phép nối. Chúng chắc chắn có thể xảy ra khi chúng buộc một kế hoạch vòng lặp lồng nhau (truy vấn phụ được đánh giá theo từng hàng) nhưng kế hoạch này bao gồm một toán tử logic chống bán nối. Các phép nối bán chống không bị giới hạn đối với các vòng lồng nhau nhưng cũng có thể sử dụng các phép nối băm hoặc hợp nhất (như trong ví dụ này).
/*Not valid syntax but better reflects the plan*/
SELECT p.ProductID,
p.ProductName
FROM Products p
LEFT ANTI SEMI JOIN [Order Details] od
ON p.ProductId = od.ProductId
Nếu [Order Details].ProductID
là NULL
-able truy vấn sau đó trở thành
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
AND NOT EXISTS (SELECT *
FROM [Order Details]
WHERE ProductId IS NULL)
Lý do cho điều này là ngữ nghĩa chính xác nếu [Order Details]
chứa bất kỳ NULL
nào ProductId
s là không trả về kết quả. Xem thêm phần tham gia chống bán và ống đếm hàng để xác minh điều này được thêm vào kế hoạch.
If Products.ProductID
cũng được thay đổi để trở thành NULL
-able truy vấn sau đó trở thành
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
AND NOT EXISTS (SELECT *
FROM [Order Details]
WHERE ProductId IS NULL)
AND NOT EXISTS (SELECT *
FROM (SELECT TOP 1 *
FROM [Order Details]) S
WHERE p.ProductID IS NULL)
Lý do cho điều đó là vì NULL
Products.ProductId
sẽ không được trả lại trong kết quả ngoại trừ nếu NOT IN
truy vấn phụ hoàn toàn không trả về kết quả (tức là [Order Details]
bảng trống). Trong trường hợp đó nó nên. Trong kế hoạch cho dữ liệu mẫu của tôi, điều này được thực hiện bằng cách thêm một kết nối chống bán khác như bên dưới.
Hiệu quả của việc này được thể hiện trong bài đăng trên blog đã được Buckley liên kết. Trong ví dụ, số lần đọc logic tăng từ khoảng 400 lên 500.000.
Ngoài ra, thực tế là một NULL
có thể giảm số lượng hàng xuống 0 làm cho việc ước tính số lượng hàng rất khó khăn. Nếu SQL Server giả định rằng điều này sẽ xảy ra nhưng thực tế không có NULL
các hàng trong dữ liệu phần còn lại của kế hoạch thực thi có thể tồi tệ hơn một cách thảm khốc, nếu đây chỉ là một phần của truy vấn lớn hơn, với các vòng lặp lồng nhau không thích hợp gây ra việc thực thi lặp lại một cây con đắt tiền chẳng hạn.
Đây không phải là kế hoạch thực thi khả thi duy nhất cho NOT IN
trên NULL
cột -able tuy nhiên. Bài viết này hiển thị một bài viết khác cho truy vấn đối với AdventureWorks2008
cơ sở dữ liệu.
Đối với NOT IN
trên NOT NULL
hoặc cột NOT EXISTS
chống lại cột nullable hoặc không nullable, nó đưa ra kế hoạch sau.
Khi cột thay đổi thành NULL
-able NOT IN
kế hoạch bây giờ trông giống như
Nó bổ sung thêm một toán tử tham gia bên trong vào kế hoạch. Bộ máy này được giải thích ở đây. Đó là tất cả để chuyển đổi tìm kiếm chỉ mục tương quan đơn lẻ trước đó trên Sales.SalesOrderDetail.ProductID = <correlated_product_id>
đến hai tìm kiếm trên mỗi hàng bên ngoài. Phần bổ sung nằm trên WHERE Sales.SalesOrderDetail.ProductID IS NULL
.
Vì điều này nằm trong một phép nối chống bán nếu cái đó trả về bất kỳ hàng nào thì lần tìm kiếm thứ hai sẽ không xảy ra. Tuy nhiên nếu Sales.SalesOrderDetail
không chứa bất kỳ NULL
nào ProductID
s nó sẽ tăng gấp đôi số hoạt động tìm kiếm được yêu cầu.