Sự khác biệt giữa KHÔNG EXISTS so với KHÔNG IN so với LEFT THAM GIA LÀ GÌ?


151

Dường như với tôi rằng bạn có thể thực hiện điều tương tự trong truy vấn SQL bằng cách sử dụng KHÔNG EXISTS, NOT IN hoặc LEFT THAM GIA Ở ĐÂU LÀ NULL. Ví dụ:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

Tôi không chắc là mình có đúng cú pháp hay không, nhưng đây là những kỹ thuật chung mà tôi đã thấy. Tại sao tôi chọn sử dụng cái này hơn cái kia? Hiệu suất có khác nhau không ...? Cái nào trong số này là nhanh nhất / hiệu quả nhất? (Nếu nó phụ thuộc vào việc thực hiện, khi nào tôi sẽ sử dụng từng cái?)


6
Nhiều công cụ SQL phổ biến cung cấp cho bạn khả năng xem kế hoạch thực hiện. Bạn thường có thể phát hiện ra sự khác biệt đáng kể về hiệu quả đối với các truy vấn tương đương logic theo cách này. Sự thành công của bất kỳ phương pháp nào phụ thuộc vào các yếu tố như kích thước bảng, chỉ số nào có mặt và các chỉ số khác.
Nông dân Chris

2
@wich: không có cơ sở dữ liệu quan tâm về chính xác những gì bạn trả lại trong EXISTSmệnh đề. Bạn có thể quay lại *, NULLhoặc bất cứ điều gì: tất cả điều này sẽ được tối ưu hóa đi.
Quassnoi

2
@wich - tại sao? Cả hai ở đây: techonthenet.com/sql/exists.php và ở đây: msdn.microsoft.com/en-us/l Library / ms188336.aspx dường như sử dụng * ...
froadie

8
@wich: đây không phải là "bày tỏ sự quan tâm". Đây là về trình phân tích cú pháp truy vấn yêu cầu bạn đặt một cái gì đó giữa SELECTFROM. Và *chỉ dễ dàng hơn để gõ. Đúng, SQLcó một số điểm tương đồng với ngôn ngữ tự nhiên, nhưng nó được phân tích cú pháp và thực thi bởi một máy, một máy được lập trình. Không phải là nó sẽ đột nhiên đột nhập vào tủ của bạn và hét lên "hãy ngừng yêu cầu thêm các trường trong một EXISTStruy vấn vì tôi không muốn phân tích chúng và sau đó ném chúng đi!". Thật sự ổn với máy tính.
Quassnoi

1
@Quassnoi nếu bạn viết mã cho mục đích duy nhất là một chiếc máy diễn giải nó thì mã sẽ trông thật kinh khủng, và thật không may, khá nhiều người làm việc như vậy. Tuy nhiên, nếu bạn viết mã bằng một quang khác, viết mã để thể hiện những gì bạn muốn máy thực hiện như một thông cáo cho các đồng nghiệp của bạn, bạn sẽ viết mã tốt hơn và dễ bảo trì hơn. Hãy thông minh, viết mã cho mọi người, không phải cho máy tính.

Câu trả lời:


139

Tóm lại:

NOT INhơi khác một chút: nó không bao giờ khớp nếu có nhưng chỉ có một NULLtrong danh sách.

  • Trong MySQL, NOT EXISTSlà một chút ít hiệu quả

  • Trong SQL Server, LEFT JOIN / IS NULLlà ít hiệu quả

  • Trong PostgreSQL, NOT INlà ít hiệu quả

  • Trong Oracle, cả ba phương pháp đều giống nhau.


1
Cảm ơn các liên kết! Và cảm ơn vì tổng quan nhanh ... Văn phòng của tôi đang chặn liên kết vì một số lý do: P nhưng tôi sẽ kiểm tra ngay khi tôi đến một máy tính thông thường.
froadie

2
Điểm khác là nếu table1 .achứa NULLcác EXISTStruy vấn sẽ không trở lại hàng này nhưng NOT INtruy vấn ý nếu table2là trống rỗng. KHÔNG IN so với KHÔNG EXISTS Cột không thể xóa: Máy chủ SQL
Martin Smith

@MartinSmith: NULL NOT IN ()đánh giá là đúng (không NULL), giống nhưNOT EXISTS (NULL = column)
Quassnoi

2
@Quassnoi - er, Điểm tốt, đã đi sai đường vòng. Các NOT EXISTSsẽ luôn trả lại hàng nhưng NOT INsẽ chỉ làm như vậy nếu truy vấn phụ trả về không có hàng.
Martin Smith

5

Nếu cơ sở dữ liệu tốt trong việc tối ưu hóa truy vấn, hai cái đầu tiên sẽ được chuyển đổi thành cái gì đó gần với cái thứ ba.

Đối với các tình huống đơn giản như những câu hỏi trong bạn, sẽ có ít hoặc không có sự khác biệt, vì tất cả chúng sẽ được thực hiện dưới dạng tham gia. Trong các truy vấn phức tạp hơn, cơ sở dữ liệu có thể không thể tham gia not innot existstruy vấn. Trong trường hợp đó, các truy vấn sẽ chậm hơn rất nhiều. Mặt khác, một phép nối cũng có thể hoạt động kém nếu không có chỉ số nào có thể được sử dụng, vì vậy chỉ vì bạn sử dụng phép nối không có nghĩa là bạn an toàn. Bạn sẽ phải kiểm tra kế hoạch thực hiện của truy vấn để biết liệu có thể có bất kỳ vấn đề về hiệu năng nào không.


2

Giả sử bạn đang tránh null, tất cả đều là cách viết chống tham gia bằng cách sử dụng SQL chuẩn.

Một thiếu sót rõ ràng là tương đương bằng cách sử dụng EXCEPT:

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

Lưu ý trong Oracle bạn cần sử dụng MINUStoán tử (có thể gọi là tên tốt hơn):

SELECT a FROM table1
MINUS
SELECT a FROM table2

Nói về cú pháp độc quyền, cũng có thể có các tương đương phi tiêu chuẩn đáng để điều tra tùy thuộc vào sản phẩm bạn đang sử dụng, ví dụ như OUTER APPLYtrong SQL Server (đại loại như):

SELECT t1.a
  FROM table1 t1
       OUTER APPLY 
       (
        SELECT t2.a
          FROM table2 t2
         WHERE t2.a = t1.a
       ) AS dt1
 WHERE dt1.a IS NULL;

0

Khi cần chèn dữ liệu vào bảng bằng khóa chính đa trường, hãy xem xét rằng nó sẽ nhanh hơn nhiều (tôi đã thử trong Access nhưng tôi nghĩ trong bất kỳ Cơ sở dữ liệu nào) không kiểm tra rằng "không tồn tại các bản ghi với các giá trị 'như vậy trong bảng", - thay vì chỉ chèn vào bảng và các bản ghi thừa (bằng phím) sẽ không được chèn hai lần.


0

Phối cảnh hiệu suất luôn tránh sử dụng các từ khóa nghịch đảo như KHÔNG IN, KHÔNG EXISTS, ... Bởi vì để kiểm tra các mục nghịch đảo DBMS cần phải chạy qua tất cả các lựa chọn có sẵn và bỏ lựa chọn nghịch đảo.


1
Và những gì bạn đề xuất là giải pháp khi bạn thực sự cần NOT?
không có

Chà, khi không có tùy chọn nguyên nhân, chúng ta cần sử dụng KHÔNG hoạt động và đó là lý do tại sao chúng tồn tại. Thực hành tốt nhất là tránh chúng khi chúng ta có bất kỳ giải pháp thay thế nào khác.
Lahiru Cooray

@encedaywhen, nếu trình tối ưu hóa chuyển đổi một truy vấn và nó trả về kết quả sai thì đó là một lỗi
David

@DuduMarkovitz: có và nếu bạn liên hệ với nhóm SQL Server và họ thừa nhận lỗi nhưng từ chối sửa vì họ nói làm như vậy có thể khiến truy vấn chạy chậm hơn, thì đó là lỗi bạn cần xử lý .
ngày

@encedaywhen - Đây không phải là một tình huống giả định mà tôi đoán :-) Bạn có còn nhớ các chi tiết lỗi không?
David TOUR TOUR Markovitz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.