IN vs OR trong Điều khoản WHERE của SQL


150

Khi làm việc với cơ sở dữ liệu lớn, hoạt động tốt hơn, INhoặcOR trong phần SQL Where?

Có sự khác biệt nào về cách chúng được thực thi không?


Dự đoán đầu tiên của tôi sẽ là OR hoạt động tốt hơn, trừ khi công cụ SQL chuyển đổi IN thành OR phía sau hậu trường. Bạn đã thấy kế hoạch truy vấn của hai?
Raj

Câu trả lời:


170

Tôi giả sử bạn muốn biết sự khác biệt hiệu suất giữa các điều sau đây:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'

Theo hướng dẫn cho MySQL nếu các giá trị không đổi INsắp xếp danh sách và sau đó sử dụng tìm kiếm nhị phân. Tôi sẽ tưởng tượng rằng ORđánh giá chúng từng cái một không theo thứ tự cụ thể. Vì vậy, INlà nhanh hơn trong một số trường hợp.

Cách tốt nhất để biết là lập hồ sơ cả trên cơ sở dữ liệu của bạn với dữ liệu cụ thể của bạn để xem cái nào nhanh hơn.

Tôi đã thử cả hai trên một MySQL với 1000000 hàng. Khi cột được lập chỉ mục, không có sự khác biệt rõ rệt về hiệu suất - cả hai đều gần như ngay lập tức. Khi cột không được lập chỉ mục, tôi nhận được các kết quả sau:

SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)

SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)

Vì vậy, trong trường hợp này phương thức sử dụng OR chậm hơn khoảng 30%. Thêm nhiều điều khoản làm cho sự khác biệt lớn hơn. Kết quả có thể khác nhau trên các cơ sở dữ liệu khác và trên dữ liệu khác.


20
Nếu trình tối ưu hóa có giá trị muối, họ nên thực hiện tương tự.
Janick Bernet

27
@inflagranti: Không có trình tối ưu hóa là hoàn hảo không may. Tối ưu hóa là các chương trình cực kỳ phức tạp và mỗi triển khai sẽ có điểm mạnh và điểm yếu riêng. Đây là lý do tại sao tôi nói bạn nên hồ sơ về một triển khai cụ thể. Tôi tưởng tượng rằng cấu trúc bổ sung của INphương thức giúp tối ưu hóa dễ dàng hơn so với toàn bộ các ORmệnh đề có thể liên quan . Tôi sẽ ngạc nhiên nếu có một động cơ mà ORphương pháp nhanh hơn, nhưng tôi không ngạc nhiên rằng có những lúc OR chậm hơn.
Đánh dấu

2
@MarkByer Không phải trình tối ưu hóa luôn thay thế nhiều ORs bằng một IN?
tymtam

36

Cách tốt nhất để tìm hiểu là nhìn vào Kế hoạch thực hiện.


Tôi đã thử nó với Oracle và nó hoàn toàn giống nhau.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );

Mặc dù truy vấn sử dụng IN, Kế hoạch thực hiện nói rằng nó sử dụngOR :

--------------------------------------------------------------------------------------    
| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |    
--------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |                  |     8 |  1416 |   163   (2)| 00:00:02 |    
|*  1 |  TABLE ACCESS FULL| PERFORMANCE_TEST |     8 |  1416 |   163   (2)| 00:00:02 |    
--------------------------------------------------------------------------------------    

Predicate Information (identified by operation id):                                       
---------------------------------------------------                                       

   1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR                
              "OBJECT_NAME"='DBMS_STANDARD')                                              

1
Điều gì xảy ra trong Oracle nếu bạn có nhiều hơn 3 giá trị mà bạn đang kiểm tra? Bạn có biết nếu Oracle không thể thực hiện tối ưu hóa tìm kiếm nhị phân giống như MySQL hay nó thực hiện nó trong cả hai trường hợp?
Mark Byers

2
@Mark Byers: Tôi đã thử cùng một truy vấn với 10 giá trị, vẫn cho kết quả như nhau. Lưu ý rằng trình tối ưu hóa đã sử dụng các giá trị của tôi theo thứ tự bảng chữ cái. Tôi sẽ không ngạc nhiên nếu Oracle thực hiện một số tối ưu hóa nội bộ của bộ lọc đó ...
Peter Lang

5
Oracle cũng có một INLIST ITERATORhoạt động, nó sẽ chọn nếu có một chỉ mục mà nó có thể sử dụng. Tuy nhiên, khi tôi đã thử nó, cả hai INORkết thúc với cùng một kế hoạch thực hiện.
Cheran Shunmugavel

7

Toán tử OR cần một quy trình đánh giá phức tạp hơn nhiều so với cấu trúc IN vì nó cho phép nhiều điều kiện, không chỉ bằng IN.

Đây là một cái giống như những gì bạn có thể sử dụng với OR nhưng không tương thích với IN: lớn hơn. lớn hơn hoặc bằng nhau, ít hơn, ít hơn hoặc bằng nhau, THÍCH và một số khác giống như lời tiên tri REGEXP_LIKE. Ngoài ra, xem xét rằng các điều kiện có thể không luôn luôn so sánh cùng một giá trị.

Đối với trình tối ưu hóa truy vấn, việc quản lý toán tử IN dễ dàng hơn vì chỉ là cấu trúc xác định toán tử OR trên nhiều điều kiện với toán tử = trên cùng một giá trị. Nếu bạn sử dụng toán tử OR, trình tối ưu hóa có thể không cho rằng bạn luôn sử dụng toán tử = trên cùng một giá trị và, nếu nó không thực hiện công phu sâu hơn và phức tạp hơn nhiều, có lẽ có thể loại trừ rằng có thể chỉ có = toán tử cho cùng một giá trị trên tất cả các điều kiện liên quan, với kết quả là các phương pháp tìm kiếm được tối ưu hóa như tìm kiếm nhị phân đã được đề cập.

[EDIT] Có lẽ trình tối ưu hóa có thể không thực hiện quy trình đánh giá IN được tối ưu hóa, nhưng điều này không loại trừ rằng một lần nó có thể xảy ra (với nâng cấp phiên bản cơ sở dữ liệu). Vì vậy, nếu bạn sử dụng toán tử OR mà công phu tối ưu hóa sẽ không được sử dụng trong trường hợp của bạn.


6

Tôi nghĩ rằng oracle đủ thông minh để chuyển đổi cái kém hiệu quả hơn (cái nào khác) thành cái khác. Vì vậy, tôi nghĩ rằng câu trả lời nên phụ thuộc vào khả năng đọc của từng người (nơi tôi nghĩ rằng INchiến thắng rõ ràng)


2

OR có ý nghĩa (từ quan điểm dễ đọc), khi có ít giá trị được so sánh. INlà đặc biệt hữu ích. khi bạn có một nguồn động, mà bạn muốn các giá trị được so sánh.

Một cách khác là sử dụng một JOINbảng tạm thời.
Tôi không nghĩ hiệu suất nên là một vấn đề, miễn là bạn có các chỉ số cần thiết.


-2

Tôi đã thực hiện một truy vấn SQL với số lượng lớn OR (350). Postgres làm điều đó 437,80ms .

Sử dụng HOẶC

Bây giờ sử dụng IN:

Sử dụng VÀO

23,18ms


4
Điều đó không hoàn toàn giống nhau, vì bạn đã sử dụng truy vấn con cho mệnh đề IN.
gliljas
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.