IN vs OR w klauzuli SQL WHERE


150

Kiedy mamy do czynienia z dużymi bazami danych, która działa lepiej, INczy ORw Whereklauzuli SQL ?

Czy jest jakaś różnica w sposobie ich wykonywania?


Moje pierwsze przypuszczenie byłoby takie, że OR działa lepiej, chyba że silnik SQL konwertuje IN na OR poza sceną. Czy widziałeś plan zapytań tych dwóch?
Raj

Odpowiedzi:


170

Zakładam, że chcesz poznać różnicę w wydajności między następującymi elementami:

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

Zgodnie z podręcznikiem MySQL, jeśli wartości są stałe, INsortuje listę, a następnie stosuje wyszukiwanie binarne. Wyobrażam sobie, że ORocenia je pojedynczo, bez określonej kolejności. Tak INjest szybciej w pewnych okolicznościach.

Najlepszym sposobem, aby się dowiedzieć, jest profilowanie obu w bazie danych za pomocą określonych danych, aby zobaczyć, które jest szybsze.

Wypróbowałem oba na MySQL z 1000000 wierszami. Gdy kolumna jest indeksowana, nie ma zauważalnej różnicy w wydajności - obie są prawie natychmiastowe. Gdy kolumna nie jest zindeksowana, otrzymałem następujące wyniki:

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)

Więc w tym przypadku metoda wykorzystująca OR jest około 30% wolniejsza. Dodanie większej liczby terminów sprawia, że ​​różnica jest większa. Wyniki mogą się różnić w przypadku innych baz danych i innych danych.


20
Jeśli optymalizator jest wart swojej soli, powinien działać tak samo.
Janick Bernet

27
@inflagranti: Żaden optymalizator nie jest niestety doskonały. Optymalizatory to niezwykle złożone programy, a każde wdrożenie będzie miało swoje mocne i słabe strony. Dlatego mówię, że powinieneś profilować się na konkretnej implementacji. Wyobrażam sobie, że dodatkowa struktura INmetody ułatwia optymalizację niż cała masa potencjalnie powiązanych ORklauzul. Zdziwiłbym się, gdyby był silnik, w którym ORmetoda jest szybsza, ale nie dziwię się, że są chwile, kiedy OR jest wolniejsze.
Mark Byers

2
@MarkByers Czy optymalizator nie może zawsze zastąpić wielu ORs ciągiem IN?
tymtam

36

Najlepszym sposobem, aby się tego dowiedzieć, jest przyjrzenie się planowi wykonania.


Wypróbowałem to z Oracle i było dokładnie to samo.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

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

Mimo że zapytanie używa IN, Plan wykonania mówi, że używa OR:

--------------------------------------------------------------------------------------    
| 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
Co dzieje się w Oracle, jeśli masz więcej niż 3 wartości, które testujesz? Czy wiesz, czy Oracle nie jest w stanie przeprowadzić takiej samej optymalizacji wyszukiwania binarnego co MySQL, czy też wykonuje ją w obu przypadkach?
Mark Byers

2
@Mark Byers: Próbowałem wykonać to samo zapytanie z 10 wartościami, wciąż ten sam wynik. Zauważ, że optymalizator zastosował moje wartości w kolejności alfabetycznej. Nie zdziwiłbym się, gdyby Oracle dokonało wewnętrznej optymalizacji tego filtru ...
Peter Lang,

5
Oracle ma również INLIST ITERATORoperację, którą wybrałaby, gdyby istniał indeks, którego mogłaby użyć. Mimo to, kiedy wypróbowałem to, oba INi ORkończyły się tym samym planem wykonania.
Cheran Shunmugavel

7

Operator OR potrzebuje znacznie bardziej złożonego procesu oceny niż konstrukcja IN, ponieważ dopuszcza wiele warunków, a nie tylko równa się IN.

Oto coś podobnego do tego, czego możesz używać z operatorem OR, ale które nie są zgodne z IN: większe. większy lub równy, mniejszy, mniejszy lub równy, LIKE, a niektóre bardziej jak wyrocznia REGEXP_LIKE. Ponadto należy wziąć pod uwagę, że warunki nie zawsze mogą porównywać tę samą wartość.

W przypadku optymalizatora zapytań łatwiej jest zarządzać operatorem IN, ponieważ jest to tylko konstrukcja, która definiuje operator OR na wielu warunkach z operatorem = na tej samej wartości. Jeśli użyjesz operatora OR, optymalizator może nie wziąć pod uwagę, że zawsze używasz operatora = na tej samej wartości, a jeśli nie wykona głębszego i znacznie bardziej złożonego opracowania, prawdopodobnie może wykluczyć, że może istnieć tylko = operatory dla tych samych wartości we wszystkich zaangażowanych warunkach, co w konsekwencji wyklucza zoptymalizowane metody wyszukiwania, takie jak wspomniane już wyszukiwanie binarne.

[EDYCJA] Prawdopodobnie optymalizator może nie zaimplementować zoptymalizowanego procesu oceny IN, ale nie wyklucza to, że może się to zdarzyć (przy aktualizacji wersji bazy danych). Jeśli więc użyjesz operatora OR, to zoptymalizowane opracowanie nie będzie używane w twoim przypadku.


6

Myślę, że wyrocznia jest wystarczająco sprytna, aby zamienić mniej wydajną (cokolwiek to jest) w drugą. Więc myślę, że odpowiedź powinna raczej zależeć od czytelności każdego (gdzie myślę, że to INwyraźnie wygrywa)


2

ORma sens (z punktu widzenia czytelności), gdy jest mniej wartości do porównania. INjest przydatne, zwł. gdy masz dynamiczne źródło, z którym chcesz porównać wartości.

Inną alternatywą jest użycie JOINtabeli tymczasowej.
Nie sądzę, aby wydajność była problemem, pod warunkiem, że masz niezbędne indeksy.


-2

Zrobiłem zapytanie SQL w dużej liczbie OR (350). Postgres robi to 437,80ms .

Użyj OR

Teraz użyj IN:

Użyj IN

23,18 ms


4
To nie jest to samo, ponieważ użyłeś podzapytania dla klauzuli IN.
gliljas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.