KHÔNG nên tránh?


14

Trong số một số nhà phát triển SQL Server, có một niềm tin rộng rãi NOT INlà rất chậm và các truy vấn nên được viết lại để chúng trả về cùng một kết quả nhưng không sử dụng các từ khóa "xấu xa". ( ví dụ ).

Có sự thật nào đó?

Chẳng hạn, có một số lỗi đã biết trong SQL Server (phiên bản nào?) Khiến các truy vấn sử dụng NOT INcó kế hoạch thực hiện kém hơn so với truy vấn tương đương sử dụng

  • một LEFT JOINkết hợp với một NULLkiểm tra hoặc
  • (SELECT COUNT(*) ...) = 0trong WHEREmệnh đề?

7
Bài viết đó rất không chính xác mặc dù. "Trong" không "phải chạy cùng một truy vấn nhiều lần cho mỗi hàng trong TableOne". Các poster dường như tin rằng IN/ NOT INsẽ luôn được thực hiện với các vòng lặp lồng nhau. Và tôi không biết những gì stops SQL Server from creating a ‘plan’được cho là có nghĩa.
Martin Smith

5
@Heinzi Bài viết mà bạn liên kết đến, nên chết trong lửa, nó đầy vô nghĩa. Giống như: "Để thay thế IN, chúng tôi sử dụng INNER THAM GIA. Chúng thực sự giống nhau." Vấn đề là, chúng không giống nhau. Tôi sẽ không tin tưởng ai đó không biết SQL cơ bản, tức là sự khác biệt giữa tham gia và bán tham gia, để phân tích bất cứ điều gì về hành vi của SQL-Server.
ypercubeᵀᴹ

Câu trả lời:


14

Tôi không nghĩ nó có liên quan gì đến việc chậm kinh khủng; nó phải làm với khả năng không chính xác. Ví dụ: được cung cấp dữ liệu sau - các đơn đặt hàng có thể được đặt bởi một khách hàng cá nhân hoặc đối tác B2B:

DECLARE @Customers TABLE(CustomerID INT);

INSERT @Customers VALUES(1),(2);

DECLARE @Orders TABLE(OrderID INT, CustomerID INT, CompanyID INT);

INSERT @Orders VALUES(10,1,NULL),(11,NULL,5);

Hãy nói rằng tôi muốn tìm tất cả các khách hàng chưa bao giờ đặt hàng. Đưa ra dữ liệu, chỉ có một: khách hàng số 2. Dưới đây là ba cách tôi có thể viết về một truy vấn để tìm thông tin đó (có những cách khác):

SELECT [NOT IN] = CustomerID FROM @Customers 
  WHERE CustomerID NOT IN (SELECT CustomerID FROM @Orders);

SELECT [NOT EXISTS] = CustomerID FROM @Customers AS c 
  WHERE NOT EXISTS (SELECT 1 FROM @Orders AS o
  WHERE o.CustomerID = c.CustomerID);

SELECT [EXCEPT] = CustomerID FROM @Customers
EXCEPT SELECT CustomerID FROM @Orders;

Các kết quả:

NOT IN
------
                 -- <-- no results. Is that what you expected?

NOT EXISTS
----------
2

EXCEPT
------
2

Bây giờ, có một số vấn đề hiệu suất là tốt, và tôi nói về chúng trong bài viết trên blog này . Tùy thuộc vào dữ liệu và chỉ mục, NOT EXISTSthường sẽ tốt hơn NOT INvà tôi không biết liệu nó có thể hoạt động kém hơn không. Bạn cũng nên lưu ý rằng EXCEPTcó thể giới thiệu một hoạt động sắp xếp riêng biệt, do đó bạn có thể kết thúc với dữ liệu khác nhau (một lần nữa, tùy thuộc vào nguồn). Và rằng LEFT OUTER JOIN ... WHERE right.column IS NULLmô hình phổ biến luôn luôn là biểu diễn tồi tệ nhất.

Martin Smith cũng có rất nhiều thông tin hỗ trợ tốt trong câu trả lời của mình về SO .

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.