Tôi đã nghe rất nhiều người dân trong những năm qua nói rằng:Sử dụng “NOT EXISTS” có được coi là thực thi SQL không?
"tham gia" khai thác được ưa thích hơn “không tồn tại”
Tại sao?
Tôi đã nghe rất nhiều người dân trong những năm qua nói rằng:Sử dụng “NOT EXISTS” có được coi là thực thi SQL không?
"tham gia" khai thác được ưa thích hơn “không tồn tại”
Tại sao?
Trong MySQL
, Oracle
, SQL Server
và PostgreSQL
, NOT EXISTS
là của cùng một hiệu quả hoặc thậm chí hiệu quả hơn LEFT JOIN/IS NULL
.
Mặc dù có vẻ như "truy vấn bên trong sẽ được thực hiện cho mỗi bản ghi từ truy vấn bên ngoài" (có vẻ là xấu đối với NOT EXISTS
và thậm chí tệ hơn cho NOT IN
, vì truy vấn thứ hai thậm chí không tương quan), nó có thể được tối ưu hóa cũng như tất cả các truy vấn khác được tối ưu hóa, sử dụng các phương thức thích hợp anti-join
.
Trong SQL Server
, trên thực tế, LEFT JOIN/IS NULL
có thể kém hiệu quả hơn NOT EXISTS/NOT IN
trong trường hợp cột cardin chưa được lập chỉ mục hoặc thấp trong bảng bên trong.
Người ta thường nghe nói rằng MySQL
là "đặc biệt xấu khi xử lý các truy vấn con".
Điều này bắt nguồn từ thực tế là MySQL
không có khả năng của bất kỳ phương thức kết nối nào ngoài vòng lặp lồng nhau, giới hạn nghiêm trọng khả năng tối ưu hóa của nó.
Trường hợp duy nhất khi một truy vấn sẽ được hưởng lợi từ viết lại subquery như một tham gia sẽ là:
SELECT *
FROM big_table
WHERE big_table_column IN
(
SELECT small_table_column
FROM small_table
)
small_table
sẽ không được truy vấn hoàn toàn cho mỗi bản ghi trong big_table
: mặc dù nó dường như không có mối tương quan, nó sẽ được ngầm tương quan của các truy vấn tối ưu và trong thực tế viết lại để một EXISTS
(sử dụng index_subquery
để tìm kiếm nhiều thứ nhất nếu cần thiết nếu small_table_column
được lập chỉ mục)
Nhưng big_table
sẽ luôn là hàng đầu, mà làm cho t truy vấn của anh ấy hoàn thành trong big * LOG(small)
thay vì đọc small * LOG(big)
.
này có thể được viết lại như
SELECT DISTINCT bt.*
FROM small_table st
JOIN big_table bt
ON bt.big_table_column = st.small_table_column
Tuy nhiên, điều này sẽ không cải thiện NOT IN
(như trái ngược với IN
). Trong MySQL
, NOT EXISTS
và LEFT JOIN/IS NULL
gần như giống nhau, vì với vòng lặp lồng nhau, bảng bên trái phải luôn dẫn đầu trong một số LEFT JOIN
.
Bạn có thể muốn đọc những bài viết này:
Trong trường hợp này bao lâu? –
@Ian: chính xác là gì? – Quassnoi
@Qnassnoi, rằng hiệu quả là về cùng một –
Điều này có thể liên quan đến quy trình tối ưu hóa ... KHÔNG tồn tại ngụ ý truy vấn phụ và "trình tối ưu hóa" thường không thực hiện công việc phụ. Mặt khác, việc tham gia có thể được giải quyết dễ dàng hơn ...
Tôi nghĩ đây là trường hợp cụ thể của MySQL. MySQL không tối ưu hóa truy vấn phụ trong IN/không phải trong/bất kỳ/không tồn tại mệnh đề, và thực sự thực hiện truy vấn phụ cho mỗi hàng được đối sánh bởi truy vấn bên ngoài. Bởi vì điều này trong MySQL, bạn nên sử dụng tham gia. Tuy nhiên, trong PostgreSQL, bạn chỉ có thể sử dụng truy vấn phụ.
@duffymo: tất cả đều sai. – Quassnoi
Tại sao điều này đóng lại? Tôi cũng tò mò về lý do. –
@Ziayo: có lẽ vì những từ "rất nhiều người". Nếu được diễn đạt "được kết hợp hiệu quả hơn" KHÔNG tồn tại ", đó sẽ là một câu hỏi hoàn hảo có thể trả lời được với" sự kiện, tài liệu tham khảo hoặc chuyên môn cụ thể ". – Quassnoi