Tôi luôn đặt mặc định là NOT EXISTS
.
Các kế hoạch thực hiện có thể giống nhau vào lúc này nhưng nếu một trong hai cột được thay đổi trong tương lai để cho phép NULL
là phiên bản NOT IN
sẽ cần phải làm việc nhiều hơn (ngay cả khi không NULL
s đang thực sự hiện diện trong dữ liệu) và ngữ nghĩa của NOT IN
nếu NULL
s là hiện tại dường như không phải là ngôn ngữ bạn muốn.
Khi không phải Products.ProductID
hoặc [Order Details].ProductID
cho phép NULL
s NOT IN
sẽ được xử lý giống hệt với truy vấn sau đây.
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
Gói chính xác có thể thay đổi nhưng đối với dữ liệu mẫu của tôi, tôi nhận được thông tin sau.
Một quan niệm sai lầm một cách hợp lý thông thường dường như là phụ truy vấn tương quan luôn "xấu" so với tham gia. Họ chắc chắn có thể là khi họ buộc một kế hoạch vòng lặp lồng nhau (truy vấn phụ được đánh giá từng hàng) nhưng kế hoạch này bao gồm một toán tử hợp lý chống bán tham gia. Chống tham gia bán không bị giới hạn trong vòng lặp lồng nhau nhưng có thể sử dụng hàm băm hoặc hợp nhất (như trong ví dụ này) cũng tham gia.
/*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 đúng nếu [Order Details]
chứa bất kỳ NULL
ProductId
s là để trở về không có kết quả. Xem thêm chống bán tham gia và hàng số spool để xác minh điều này được thêm vào kế hoạch.
Nếu 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 một trong đó là bởi vì một NULL
Products.ProductId
không nên được trả lại trong kết quả trừ nếu truy vấn phụ NOT IN
không trả lại kết quả nào (ví dụ: bảng [Order Details]
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 liên kết chống bán khác như dưới đây.
Hiệu quả của việc này được thể hiện trong the blog post already linked by Buckley. Trong ví dụ có số lần đọc hợp lý tăng từ khoảng 400 đến 500.000.
Ngoài ra thực tế là một đơn NULL
có thể làm giảm số lượng hàng bằng không làm cho ước tính số lượng thẻ rất khó. Nếu SQL Server giả định rằng điều này sẽ xảy ra nhưng trên thực tế không có các hàng NULL
trong dữ liệu phần còn lại của kế hoạch thực hiện có thể tồi tệ hơn, nếu đây chỉ là một phần của truy vấn lớn hơn, with inappropriate nested loops causing repeated execution of an expensive sub tree for example.
Tuy nhiên, đây không phải là kế hoạch thực hiện duy nhất có thể cho số NOT IN
trên cột NULL
. This article shows another one cho truy vấn đối với cơ sở dữ liệu AdventureWorks2008
.
Đối với NOT IN
trên cột NOT NULL
hoặc NOT EXISTS
đối với cột có thể vô hiệu hoặc không có giá trị, nó cung cấp gói sau đây.
Khi những thay đổi cột để NULL
-able kế hoạch NOT IN
bây giờ trông như
Nó bổ sung thêm một bên tham gia điều hành kế hoạch. Thiết bị này là explained here. Đó là tất cả để chuyển đổi các chỉ số tương quan duy nhất trước đó tìm kiếm trên Sales.SalesOrderDetail.ProductID = <correlated_product_id>
đến hai tìm kiếm cho mỗi hàng bên ngoài. Phần bổ sung nằm trên WHERE Sales.SalesOrderDetail.ProductID IS NULL
.
Vì đây là dưới sự tham gia chống bán nếu người đó trả về bất kỳ hàng nào, 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
ProductID
s nó sẽ tăng gấp đôi số lượng hoạt động tìm kiếm bắt buộc.
bạn đã thử kế hoạch bằng cách sử dụng kết nối bên trái có null không? – Sebas
Tôi tự hỏi liệu Cơ sở dữ liệu có khác nhau không, nhưng trong điểm chuẩn mới nhất của tôi đối với PostgreSQL, truy vấn 'KHÔNG IN' này:" CHỌN "A". * FROM "A" WHERE "A". "Id" NOT IN (SELECT "B". " "TỪ" B "Ở ĐÂU" B "." Uid "= 2)' nhanh hơn gần 30 lần so với 'KHÔNG TUYỆT VỜI': 'CHỌN" A ". * TỪ" A "Ở ĐÂU (KHÔNG (DANH SÁCH (CHỌN 1 TỪ "B" WHERE "B". "User_id" = 2 AND "B". "Aid" = "A". "Id"))) ' –
Có thể trùng lặp của [Sự khác nhau giữa NOT EXISTS vs. NOT IN vs LEFT JOIN WHERE IS NULL?] (Http://stackoverflow.com/questions/2246772/whats-the-difference-between-not-exists-vs-not-in-vs-left-join-where-is-null) – rcdmk