Kiedy mamy do czynienia z dużymi bazami danych, która działa lepiej, IN
czy OR
w Where
klauzuli SQL ?
Czy jest jakaś różnica w sposobie ich wykonywania?
Kiedy mamy do czynienia z dużymi bazami danych, która działa lepiej, IN
czy OR
w Where
klauzuli SQL ?
Czy jest jakaś różnica w sposobie ich wykonywania?
Odpowiedzi:
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, IN
sortuje listę, a następnie stosuje wyszukiwanie binarne. Wyobrażam sobie, że OR
ocenia je pojedynczo, bez określonej kolejności. Tak IN
jest 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.
IN
metody ułatwia optymalizację niż cała masa potencjalnie powiązanych OR
klauzul. Zdziwiłbym się, gdyby był silnik, w którym OR
metoda jest szybsza, ale nie dziwię się, że są chwile, kiedy OR jest wolniejsze.
OR
s ciągiem IN
?
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')
INLIST ITERATOR
operację, którą wybrałaby, gdyby istniał indeks, którego mogłaby użyć. Mimo to, kiedy wypróbowałem to, oba IN
i OR
kończyły się tym samym planem wykonania.
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.
OR
ma sens (z punktu widzenia czytelności), gdy jest mniej wartości do porównania.
IN
jest przydatne, zwł. gdy masz dynamiczne źródło, z którym chcesz porównać wartości.
Inną alternatywą jest użycie JOIN
tabeli tymczasowej.
Nie sądzę, aby wydajność była problemem, pod warunkiem, że masz niezbędne indeksy.
Zrobiłem zapytanie SQL w dużej liczbie OR (350). Postgres robi to 437,80ms .
Teraz użyj IN:
23,18 ms