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?
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);1row fetched in0.0032(1.2679 seconds)SELECT COUNT(*)FROM t_inner WHERE val =1000OR val =2000OR val =3000OR val =4000OR val =5000OR val =6000OR val =7000OR val =8000OR val =9000;1row fetched in0.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.
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.
CREATETABLE 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')
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.
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)
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.
Odpowiedzi:
Zakładam, że chcesz poznać różnicę w wydajności między następującymi elementami:
Zgodnie z podręcznikiem MySQL, jeśli wartości są stałe,
IN
sortuje listę, a następnie stosuje wyszukiwanie binarne. Wyobrażam sobie, żeOR
ocenia je pojedynczo, bez określonej kolejności. TakIN
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:
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.
źródło
IN
metody ułatwia optymalizację niż cała masa potencjalnie powiązanychOR
klauzul. Zdziwiłbym się, gdyby był silnik, w którymOR
metoda jest szybsza, ale nie dziwię się, że są chwile, kiedy OR jest wolniejsze.OR
s ciągiemIN
?Najlepszym sposobem, aby się tego dowiedzieć, jest przyjrzenie się planowi wykonania.
Wypróbowałem to z Oracle i było dokładnie to samo.
Mimo że zapytanie używa
IN
, Plan wykonania mówi, że używaOR
:źródło
INLIST ITERATOR
operację, którą wybrałaby, gdyby istniał indeks, którego mogłaby użyć. Mimo to, kiedy wypróbowałem to, obaIN
iOR
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.
źródło
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
IN
wyraźnie wygrywa)źródło
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.
źródło
Zrobiłem zapytanie SQL w dużej liczbie OR (350). Postgres robi to 437,80ms .
Teraz użyj IN:
23,18 ms
źródło