Wydajność SQL JOIN vs IN?


164

Mam przypadek, w którym użycie JOIN lub IN da mi prawidłowe wyniki ... Który z nich ma zwykle lepszą wydajność i dlaczego? Ile to zależy od używanego serwera bazy danych? (FYI używam MSSQL)


:) Właściwie to szukałem innego artykułu, którego użyłem, kiedy szukałem czegoś podobnego jakiś czas temu, i przez pomyłkę natknąłem się na ten
artykuł

Przepraszam za możliwy duplikat ... nie znalazłem tego pytania podczas wyszukiwania
Polaris878

Odpowiedzi:


196

Ogólnie rzecz biorąc, INi JOINsą różne pytania, które mogą dawać różne wyniki.

SELECT  a.*
FROM    a
JOIN    b
ON      a.col = b.col

to nie to samo co

SELECT  a.*
FROM    a
WHERE   col IN
        (
        SELECT  col
        FROM    b
        )

chyba że b.coljest wyjątkowy.

Jest to jednak synonim pierwszego zapytania:

SELECT  a.*
FROM    a
JOIN    (
        SELECT  DISTINCT col
        FROM    b
        )
ON      b.col = a.col

Jeśli kolumna łącząca jest UNIQUEi jest oznaczona jako taka, oba te zapytania dają ten sam plan w programie SQL Server.

Jeśli nie, to INjest szybszy niż JOINwłączony DISTINCT.

Zobacz ten artykuł na moim blogu, aby uzyskać szczegółowe informacje na temat wydajności:


Tak, ma sens, że wykonaliby to samo, jeśli łącząca kolumna jest wyjątkowa (co jest w moim przypadku)
Polaris878

1
Podobnie, czy powinienem używać IN (SELECT DISTINCT ...) czy po prostu IN (SELECT ...)?
moo

8
@ orlandu63: INimplikuje DISTINCT. SQL Serverjest wystarczająco inteligentny, aby to zauważyć i wygeneruje te same plany dla obu zapytań. Nie jestem jednak pewien, jak RDBMSzachowają się inni .
Quassnoi

>> IN i JOIN to różne zapytania, które mogą dać różne wyniki. Czy możesz wyjaśnić, dlaczego miałoby to generować inny wynik w tym przypadku, nawet jeśli b.col nie jest unikalne?
Abhijeet,



6

Trudno to powiedzieć - aby naprawdę dowiedzieć się, który z nich działa lepiej, musiałbyś właściwie sprofilować czasy wykonania.

Ogólnie rzecz biorąc, myślę, że jeśli masz indeksy w kolumnach klucza obcego i używasz tylko (lub głównie) warunków INNER JOIN, to JOIN będzie nieco szybsze.

Ale gdy tylko zaczniesz używać OUTER JOIN lub jeśli nie masz indeksów kluczy obcych, IN może być szybsze.

Marc


Też o tym myślałem ... ponieważ wydaje się, że JOIN jest bardziej powszechnym przypadkiem i prawdopodobnie byłby zoptymalizowany
Polaris878

4

Ciekawe podsumowanie logicznych różnic: SQL Server: JOIN vs IN vs EXISTS - logiczna różnica

Jestem prawie pewien, że zakładając, że relacje i indeksy są zachowane, funkcja Join będzie ogólnie działać lepiej (praca z tą operacją wymaga więcej wysiłku niż innych). Jeśli myślisz o tym koncepcyjnie, to jest to różnica między 2 zapytaniami a 1 zapytaniem.

Musisz podłączyć go do Query Analyzer i wypróbować, a zobaczysz różnicę. Spójrz także na Plan wykonania zapytań i spróbuj zminimalizować kroki.


4

Ten wątek jest dość stary, ale wciąż często się o nim wspomina. Jak na mój gust, jest to trochę niekompletne, ponieważ istnieje inny sposób zapytania bazy danych za pomocą słowa kluczowego EXISTS, który, jak stwierdziłem, jest szybszy niż nie.

Więc jeśli interesują Cię tylko wartości z tabeli a, możesz użyć tego zapytania:

SELECT  a.*
FROM    a
WHERE   EXISTS (
    SELECT  *
    FROM    b
    WHERE   b.col = a.col
    )

Różnica może być ogromna, jeśli kolumna nie jest indeksowana, ponieważ db nie musi znajdować wszystkich rekordów w kolumnie b, które mają tę samą wartość w kolumnie, musi tylko znaleźć pierwszy. Jeśli nie ma indeksu na b.col i wiele rekordów w tabeli ba skanowania może być konsekwencją. Z IN lub JOIN byłoby to pełne skanowanie tabeli, z EXISTS byłoby to tylko częściowe skanowanie tabeli (do czasu znalezienia pierwszego pasującego rekordu).

Jeśli jest wiele rekordów w b, które mają tę samą wartość col, zmarnujesz również dużo pamięci na wczytanie wszystkich tych rekordów do tymczasowej przestrzeni tylko po to, aby stwierdzić, że twój warunek jest spełniony. W przypadku istnienia można tego zwykle uniknąć.

Często stwierdzałem, że ISTNIEJE szybciej niż W, nawet jeśli istnieje indeks. Zależy to od systemu bazy danych (optymalizatora), danych i wreszcie od rodzaju używanego indeksu.


3
W MSSql fakt, że istnieje, jest lepszy niż IN, wydaje się nieprawdą. Więcej informacji można znaleźć na stronie: objaśnienie.com /2009/ 06/ 16/in-vs-join-vs-exists. Tutaj możesz przeczytać, że: „Wiele osób uważa, że ​​EXISTS jest bardziej wydajne niż IN, ponieważ EXISTS zwraca tylko jeden wiersz. nie dotyczy SQL Server. Jak widać z powyższych przykładów, EXISTS i IN tworzą dokładnie te same plany. Dzieje się tak, ponieważ EXISTS jest bardziej elastyczne niż IN. IN można zawsze przepisać jako EXISTS (używając prostego warunku WHERE z równaniem ), ale nie odwrotnie ”.
Micaël Félix

3

Implementacja każdej bazy danych, ale prawdopodobnie możesz się domyślić, że wszystkie one rozwiązują typowe problemy w mniej więcej ten sam sposób. Jeśli używasz MSSQL, spójrz na wygenerowany plan wykonania. Możesz to zrobić, włączając profiler i plany wykonania. To da ci wersję tekstową po uruchomieniu polecenia.

Nie jestem pewien, jakiej wersji MSSQL używasz, ale możesz uzyskać graficzną wersję w SQL Server 2000 w analizatorze zapytań. Jestem pewien, że ta funkcjonalność czai się gdzieś w SQL Server Studio Manager w późniejszych wersjach.

Zapoznaj się z planem egzekucji. O ile to możliwe, unikaj skanowania tabeli, chyba że oczywiście twoja tabela jest mała. W takim przypadku skanowanie tabeli jest szybsze niż użycie indeksu. Zapoznaj się z różnymi operacjami łączenia, które produkuje każdy inny scenariusz.


1

Optymalizator powinien być wystarczająco inteligentny, aby w obu przypadkach dawać ten sam wynik dla zwykłych zapytań. Sprawdź plan wykonania i powinni dać ci to samo. Jeśli tego nie zrobią, normalnie uznałbym JOIN za szybsze. Jednak wszystkie systemy są różne, więc dla pewności należy profilować kod w systemie.


5
Powinieneś zrobić? Może. Czy to? Nie. Zobacz mój post.
cletus
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.