Cập nhật:
Các bài viết này trong blog của tôi mô tả sự khác biệt giữa các phương pháp một cách chi tiết hơn:
-
NOT IN
so vớiNOT EXISTS
so vớiLEFT JOIN / IS NULL
:SQL Server
-
NOT IN
so vớiNOT EXISTS
so vớiLEFT JOIN / IS NULL
:PostgreSQL
-
NOT IN
so vớiNOT EXISTS
so vớiLEFT JOIN / IS NULL
:Oracle
-
NOT IN
so vớiNOT EXISTS
so vớiLEFT JOIN / IS NULL
:MySQL
Có ba cách để thực hiện một truy vấn như vậy:
-
LEFT JOIN / IS NULL
:SELECT * FROM common LEFT JOIN table1 t1 ON t1.common_id = common.common_id WHERE t1.common_id IS NULL
-
NOT EXISTS
:SELECT * FROM common WHERE NOT EXISTS ( SELECT NULL FROM table1 t1 WHERE t1.common_id = common.common_id )
-
NOT IN
:SELECT * FROM common WHERE common_id NOT IN ( SELECT common_id FROM table1 t1 )
Khi table1.common_id
không thể nullable, tất cả các truy vấn này đều giống nhau về mặt ngữ nghĩa.
Khi nó là nullable, NOT IN
khác, vì IN
(và do đó, NOT IN
) trả về NULL
khi một giá trị không khớp với bất kỳ thứ gì trong danh sách chứa NULL
.
Điều này có thể khó hiểu nhưng có thể trở nên rõ ràng hơn nếu chúng ta nhớ lại cú pháp thay thế cho điều này:
common_id = ANY
(
SELECT common_id
FROM table1 t1
)
Kết quả của điều kiện này là một sản phẩm boolean của tất cả các phép so sánh trong danh sách. Tất nhiên, một NULL
giá trị mang lại NULL
kết quả hiển thị toàn bộ kết quả NULL
quá.
Chúng tôi không bao giờ có thể chắc chắn rằng common_id
không bằng bất kỳ giá trị nào từ danh sách này, vì ít nhất một trong các giá trị là NULL
.
Giả sử chúng ta có những dữ liệu này:
common
--
1
3
table1
--
NULL
1
2
LEFT JOIN / IS NULL
và NOT EXISTS
sẽ trả về 3
, NOT IN
sẽ trả lại không có gì (vì nó sẽ luôn đánh giá thành FALSE
hoặc NULL
).
Trong MySQL
, trong trường hợp trên cột không thể nullable, LEFT JOIN / IS NULL
và NOT IN
hiệu quả hơn một chút (vài phần trăm) so với NOT EXISTS
. Nếu cột có giá trị rỗng, NOT EXISTS
là hiệu quả nhất (một lần nữa, không nhiều).
Trong Oracle
, cả ba truy vấn đều mang lại các kế hoạch giống nhau (ANTI JOIN
).
Trong SQL Server
, NOT IN
/ NOT EXISTS
hiệu quả hơn, vì LEFT JOIN / IS NULL
không thể được tối ưu hóa thành ANTI JOIN
bằng trình tối ưu hóa của nó.
Trong PostgreSQL
, LEFT JOIN / IS NULL
và NOT EXISTS
hiệu quả hơn NOT IN
, sine chúng được tối ưu hóa thành Anti Join
, trong khi NOT IN
sử dụng hashed subplan
(hoặc thậm chí là một subplan
đơn giản nếu truy vấn con quá lớn để băm)