Hiệu suất của SQL Server IN so với EXISTS


115

Tôi tò mò cách nào dưới đây sẽ hiệu quả hơn?

Tôi luôn thận trọng khi sử dụng INvì tôi tin rằng SQL Server biến tập kết quả thành một IFtuyên bố lớn . Đối với một tập kết quả lớn, điều này có thể dẫn đến hiệu suất kém. Đối với các tập kết quả nhỏ, tôi không chắc là tốt hơn. Đối với tập kết quả lớn, sẽ không EXISTShiệu quả hơn?

WHERE EXISTS (SELECT * FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

so với

WHERE bx.BoxID IN (SELECT BoxID FROM Base WHERE [Rank = 2])

8
Cách tốt nhất để tìm hiểu là dùng thử và thực hiện một số bệnh sởi.
Klaus Byskov Pedersen

10
đã trở thành một bản sao gazillion cho điều này ......
marc_s

5
@marc_s - Có lẽ là như vậy, nhưng trong thời gian đó, tôi sẽ phải xem qua tất cả các bài viết về chủ đề này và tìm thấy một bài phù hợp với trường hợp của tôi, tôi đã có bốn câu trả lời cho câu hỏi của mình.
Randy Minder

7
FYI nếu bạn muốn các hầu hết các cách performant, bạn có thể select 1 from Base...vào bạn where existsvì bạn không thực sự quan tâm đến kết quả, chỉ là một hàng thực sự tồn tại.
brad

2
@marc_s thật sự rất buồn, vì tôi đã dành thời gian để xem qua các bài đăng để không thêm bất kỳ thùng rác nào vào stackoverflow. Tôi không cần một câu trả lời phù hợp để hoàn thành công việc của mình. Đó là kiểu suy nghĩ đã thêm một bản sao Gazillion thay vì chỉ một số ít có câu trả lời hay
IvoC

Câu trả lời:


140

EXISTS sẽ nhanh hơn bởi vì một khi động cơ đã tìm thấy một cú đánh, nó sẽ thoát khỏi việc tìm kiếm như điều kiện đã được chứng minh là đúng.

Với IN, nó sẽ thu thập tất cả các kết quả từ truy vấn phụ trước khi xử lý thêm.


4
Đó là một điểm hay. Câu lệnh IN yêu cầu SQL Server tạo một tập kết quả hoàn chỉnh và sau đó tạo một câu lệnh IF lớn mà tôi nghĩ.
Randy Minder

72
Điều này đã từng đúng nhưng trong các phiên bản hiện tại (ít nhất là năm 2008), trình tối ưu hóa thông minh hơn nhiều ... nó thực sự đối xử với IN () giống như EXISTS ().
Aaron Bertrand

11
@Aaron - vâng, thông thường, trình tối ưu hóa sẽ tạo ra một kế hoạch tốt hơn. Tuy nhiên, dựa vào các phím tắt nội bộ có thể gây bất lợi trong các tình huống phức tạp hơn.
Scott Coates

2
Điều này chỉ đơn giản là sai. Đó là vào năm 2010 và vẫn còn.
Magnus

2
IN và EXISTS có cùng một kế hoạch truy vấn và IO. Không có lý do để nghĩ rằng họ là khác nhau trong hiệu suất. kiểm tra số liệu thống kê thời gian của bạn và tự
bồi thường

40

Câu trả lời được chấp nhận là thiển cận và câu hỏi hơi lỏng lẻo trong đó:

1) Không đề cập rõ ràng liệu chỉ số bao phủ có mặt ở bên trái, bên phải hay cả hai bên.

2) Không tính đến kích thước của bộ bên trái đầu vào và bộ bên phải đầu vào.
(Câu hỏi chỉ đề cập đến một tập kết quả tổng thể lớn ).

Tôi tin rằng trình tối ưu hóa đủ thông minh để chuyển đổi giữa "trong" so với "tồn tại" khi có sự khác biệt đáng kể về chi phí do (1) và (2), nếu không, nó có thể chỉ được sử dụng như một gợi ý (ví dụ: tồn tại để khuyến khích sử dụng một chỉ số có thể tìm kiếm ở phía bên phải).

Cả hai biểu mẫu có thể được chuyển đổi để tham gia biểu mẫu trong nội bộ, đảo ngược thứ tự tham gia và chạy dưới dạng vòng lặp, băm hoặc hợp nhất - dựa trên số lượng hàng ước tính (trái và phải) và tồn tại chỉ mục ở bên trái, phải hoặc cả hai bên.


3
không biết tại sao câu trả lời xuất sắc này lại không được chú ý nữa. Hiểu chỉ số / cấu trúc cho cả hai bên có thể tác động đến tôi đồng ý. Nói hay lắm.
SheldonH

Trình tối ưu hóa luôn đưa ra cùng một kế hoạch cho INEXISTS. Hãy thử và đưa ra bất kỳ trường hợp nào họ không có cùng một kế hoạch (mặc dù điều này không áp dụng cho NOT INNOT EXISTS)
Martin Smith

@MartinSmith Tôi giả sử bạn biết những gì bạn đang nói, nhưng bạn có bằng chứng nào cho thấy các kế hoạch luôn giống nhau không? Nếu vậy, nó sẽ làm sáng tỏ sự bất đồng kéo dài hàng thập kỷ ở đây.
MarredCheese

@MarredCheese - trách nhiệm thuộc về những người cho rằng việc tạo ra một ví dụ duy nhất về điều này là rất khác nhau
Martin Smith

37

Tôi đã thực hiện một số thử nghiệm trên SQL Server 2005 và 2008 và trên cả EXISTS và IN đều quay lại với cùng một kế hoạch thực hiện thực tế, như những gì khác đã nêu. Trình tối ưu hóa là tối ưu. :)

Mặc dù vậy, đôi khi cần lưu ý, EXISTS, IN và THAM GIA có thể trả về các kết quả khác nhau nếu bạn không đặt đúng câu hỏi của mình: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210 .aspx


5

Có rất nhiều câu trả lời sai lệch ở đây, bao gồm cả câu trả lời được đánh giá cao (mặc dù tôi không tin rằng ops của họ có nghĩa là có hại). Câu trả lời ngắn gọn là: Đây là giống nhau.

Có nhiều từ khóa trong ngôn ngữ SQL (T-), nhưng cuối cùng, điều duy nhất thực sự xảy ra trên phần cứng là các hoạt động như đã thấy trong kế hoạch truy vấn thực hiện.

Hoạt động quan hệ (lý thuyết toán học) chúng ta thực hiện khi chúng ta gọi [NOT] IN[NOT] EXISTSlà bán tham gia (chống tham gia khi sử dụng NOT). Không phải ngẫu nhiên mà các hoạt động của máy chủ sql tương ứng có cùng tên . Không có hoạt động nào đề cập đến INhoặc EXISTSbất cứ nơi nào - chỉ có (chống) bán tham gia. Vì vậy, không có cách nào tương đương logic INso vớiEXISTS lựa chọn sự lựa chọn có thể ảnh hưởng đến hiệu suất bởi vì có một cách duy nhất, đó là hoạt động thực thi (chống) bán tham gia, để có được kết quả của chúng .

Một ví dụ:

Truy vấn 1 ( kế hoạch )

select * from dt where dt.customer in (select c.code from customer c where c.active=0)

Truy vấn 2 ( kế hoạch )

select * from dt where exists (select 1 from customer c where c.code=dt.customer and c.active=0)

Bạn đã thử nó chưa? Nếu vậy, bạn có thể chia sẻ SQL và kết quả của bạn không?
UnhandledEx805Sean

Đã thử nó nhiều lần. Tôi có thể tạo một trường hợp thử nghiệm khác, và tôi sẽ, nhưng một trường hợp thử nghiệm không có nghĩa là trình tối ưu hóa sẽ thực hiện cùng một kế hoạch trên các bảng với các số liệu thống kê khác nhau. Điều này có thể khiến ai đó nghĩ rằng câu trả lời là một phần - nhưng sự tồn tại của nhiều nhà khai thác semijoin là thực tế. Có lẽ tôi sẽ tìm thấy một danh sách ở đâu đó và liên kết nó.
George Menoutis

5

Tôi sẽ đi với EXISTS qua IN, xem liên kết dưới đây:

SQL Server: THAM GIA vs IN vs EXISTS - sự khác biệt logic

Có một quan niệm sai lầm phổ biến rằng IN hành xử bình đẳng với EXISTS hoặc THAM GIA về kết quả trả về. Đơn giản là nó sai.

IN: Trả về true nếu một giá trị được chỉ định khớp với bất kỳ giá trị nào trong truy vấn con hoặc danh sách.

Tồn tại: Trả về true nếu truy vấn con chứa bất kỳ hàng nào.

Tham gia: Tham gia 2 kết quả trên cột tham gia.

Blog tín dụng: https://stackoverflow.com/users/31345/mladen-prajdic


Wow, cảm ơn bạn cho blog của bạn và giải thích.
Christian Müller

3

Các kế hoạch thực hiện thường giống hệt nhau trong các trường hợp này, nhưng cho đến khi bạn thấy các yếu tố tối ưu hóa trong tất cả các khía cạnh khác của chỉ mục, v.v., bạn thực sự sẽ không bao giờ biết.


3

Vì vậy, IN không giống như EXISTS và nó sẽ không tạo ra cùng một kế hoạch thực hiện.

Thông thường EXISTS được sử dụng trong truy vấn con tương quan, điều đó có nghĩa là bạn sẽ THAM GIA truy vấn bên trong EXISTS với truy vấn bên ngoài của bạn. Điều đó sẽ thêm nhiều bước để tạo kết quả khi bạn cần giải các phép nối truy vấn bên ngoài và truy vấn bên trong nối với nhau sau đó khớp với mệnh đề của chúng để nối cả hai.

Thông thường IN được sử dụng mà không tương quan truy vấn bên trong với truy vấn bên ngoài và điều đó có thể được giải quyết chỉ trong một bước (trong trường hợp tốt nhất).

Xem xét điều này:

  1. Nếu bạn sử dụng IN và kết quả truy vấn bên trong là hàng triệu hàng giá trị riêng biệt, nó có thể sẽ thực hiện SLOWER so với EXISTS khi truy vấn EXISTS được thực hiện (có các chỉ mục phù hợp để tham gia với truy vấn bên ngoài).

  2. Nếu bạn sử dụng EXISTS và việc tham gia với truy vấn bên ngoài của bạn rất phức tạp (mất nhiều thời gian hơn để thực hiện, không có chỉ mục phù hợp), nó sẽ làm chậm truy vấn theo số lượng hàng trong bảng bên ngoài, đôi khi thời gian ước tính để hoàn thành có thể tính bằng ngày. Nếu số lượng hàng có thể chấp nhận được đối với phần cứng cụ thể của bạn hoặc số lượng dữ liệu chính xác (ví dụ: ít giá trị DISTINCT trong một tập dữ liệu lớn) IN có thể thực hiện nhanh hơn EXISTS.

  3. Tất cả những điều trên sẽ được lưu ý khi bạn có số lượng hàng trên mỗi bảng (theo công bằng tôi có nghĩa là một cái gì đó vượt quá ngưỡng xử lý CPU và / hoặc ngưỡng ram của bạn để lưu vào bộ đệm).

Vì vậy, TRẢ LỜI là nó TIỀN. Bạn có thể viết một truy vấn phức tạp bên trong IN hoặc EXISTS, nhưng theo nguyên tắc thông thường, bạn nên thử sử dụng IN với một tập hợp các giá trị riêng biệt và EXISTS giới hạn khi bạn có nhiều hàng với nhiều giá trị riêng biệt.

Mẹo nhỏ là giới hạn số lượng hàng được quét.

Trân trọng,

Mariano


1

Để tối ưu hóa EXISTS , phải rất chữ; một cái gì đó chỉ cần có ở đó, nhưng bạn thực sự không cần bất kỳ dữ liệu nào được trả về từ truy vấn phụ tương quan. Bạn chỉ đang đánh giá một điều kiện Boolean.

Vì thế:

WHERE EXISTS (SELECT TOP 1 1 FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

Bởi vì truy vấn phụ tương quan là RBAR, lần truy cập kết quả đầu tiên làm cho điều kiện đúng và nó không được xử lý nữa.


Tôi luôn cực kỳ thận trọng khi sử dụng mã hóa LEFT THAM GIA + NULL, bởi vì rất dễ bị bỏ sót hoặc sai lệch kết quả nếu bạn không cẩn thận trong việc xử lý NULL. Tôi rất hiếm khi gặp tình huống EXISTS hoặc CTE (để tìm bản sao hoặc chèn tổng hợp cho dữ liệu bị thiếu), cả hai đều không đáp ứng các yêu cầu giống nhau và vượt trội so với LEFT THAM GIA + NULL
Josh Lewis

3
TOP 1 phải hoàn toàn không liên quan (hoặc dự phòng sự kiện) khi được sử dụng với EXISTS. EXISTS luôn trả về ngay khi nó tìm thấy bất kỳ hàng phù hợp.
Karl Kieninger

Tôi đã không thấy bất kỳ lợi ích hiệu suất với phương pháp này cho đến nay. Vui lòng hiển thị một số ảnh chụp màn hình của Kế hoạch thực hiện
DaFi4

-1

Ra khỏi đỉnh đầu và không được đảm bảo là chính xác: Tôi tin rằng lần thứ hai sẽ nhanh hơn trong trường hợp này.

  1. Trong trường hợp đầu tiên, truy vấn con tương quan có thể sẽ khiến truy vấn con được chạy cho mỗi hàng.
  2. Trong ví dụ thứ hai, truy vấn con chỉ nên chạy một lần, vì không tương quan.
  3. Trong ví dụ thứ hai, IN chí sẽ ngắn mạch ngay khi tìm thấy sự trùng khớp.
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.