2011-07-21 18 views
6

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?

+4

@duffymo: tất cả đều sai. – Quassnoi

+1

Tại sao điều này đóng lại? Tôi cũng tò mò về lý do. –

+0

@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

Trả lời

9

Trong MySQL, Oracle, SQL ServerPostgreSQL, 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 EXISTSLEFT 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:

+0

Trong trường hợp này bao lâu? –

+0

@Ian: chính xác là gì? – Quassnoi

+0

@Qnassnoi, rằng hiệu quả là về cùng một –

0

Đ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 ...

0

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ụ.

+1

Nó tối ưu hóa tất cả các mệnh đề này. Vui lòng đọc http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/ – Quassnoi

+0

@Darhazer, bạn có vẻ mắc kẹt trong phiên bản MySQL 4. – Johan

+0

@Johan: ... cũng đã tối ưu hóa tất cả các cấu trúc này. – Quassnoi

Các vấn đề liên quan