Czy istnieje różnica w wykonaniu między warunkiem JOIN a warunkiem WHERE?

17

Czy istnieje różnica w wydajności między tymi dwoma przykładowymi zapytaniami?

Zapytanie 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

Zapytanie 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

Zauważ, że jedyną różnicą jest umieszczenie warunku uzupełniającego; pierwszy używa WHEREklauzuli, a drugi dodaje warunek do ONklauzuli.

Kiedy uruchamiam te zapytania w moim systemie Teradata, plany wyjaśniania są identyczne, a krok DOŁĄCZ pokazuje w każdym przypadku dodatkowy warunek. Jednak w przypadku tego pytania SO dotyczącego MySQL jedna z odpowiedzi sugerowała, że ​​preferowany jest drugi styl, ponieważ WHEREprzetwarzanie następuje po dokonaniu połączeń.

Czy przy kodowaniu takich zapytań należy przestrzegać ogólnej zasady? Domyślam się, że musi to zależeć od platformy, ponieważ oczywiście nie ma to wpływu na moją bazę danych, ale być może jest to tylko funkcja Teradata. A jeśli zależy to od platformy, bardzo chciałbym uzyskać kilka odniesień do dokumentacji; Naprawdę nie wiem, czego szukać.

BellevueBob
źródło
9
Jest to zależne od platformy, ponieważ zależy od tego, jak optymalizator RDBMS radzi sobie z analizowaniem i optymalizacją.
Philᵀᴹ
8
I ta odpowiedź w powiązanym pytaniu zasługuje na kilka głosów negatywnych. Nawet prymitywny optymalizator MySQL zrozumiałby, że te proste zapytania są równoważne i że „klauzula WHERE jest oceniana po wykonaniu wszystkich połączeń” jest prawdziwa tylko na poziomie logicznym, a nie w rzeczywistości.
ypercubeᵀᴹ
1
Naprawdę nie duplikat; to pytanie i odpowiedzi porównywały składnię „niejawną” z „jawną” JOIN. Pytam konkretnie o dodatkowe warunki łączenia.
BellevueBob,
Nie odważę się opublikować odpowiedzi, ponieważ próbowałem tego wcześniej i otrzymałem wiele głosów negatywnych. Kiedy jest wiele sprzężeń, mam doświadczenie, że wprowadzenie warunku do złączenia skutkuje lepszym planem zapytań (filtrowano wcześnie). Nadal te same wyniki.
paparazzo

Odpowiedzi:

14

Według rozdziału 9 (Parser i optymalizator), Sasha Pachev , strona 172 książki Understanding MySQL Internal.

Zrozumienie wewnętrznych elementów MySQL

oto podział oceny zapytania jako następujące zadania:

  • Określ klucze, których można użyć do pobrania rekordów z tabel, i wybierz najlepszy dla każdej tabeli.
  • Dla każdej tabeli zdecyduj, czy skanowanie tabeli jest lepsze niż czytanie na kluczu. Jeśli istnieje wiele rekordów pasujących do wartości klucza, zalety klucza są zmniejszone, a skanowanie tabeli staje się szybsze.
  • Określ kolejność łączenia tabel, gdy w zapytaniu występuje więcej niż jedna tabela.
  • Przepisz klauzule WHERE, aby wyeliminować martwy kod, zmniejszając niepotrzebne obliczenia i zmieniając ograniczenia, tam gdzie to możliwe, aby otworzyć drogę do używania kluczy.
  • Wyeliminuj nieużywane tabele ze złączenia.
  • Określ, czy można używać kluczy ORDER BYi GROUP BY.
  • Spróbuj uprościć podzapytania, a także określić, w jakim stopniu ich wyniki mogą być buforowane.
  • Scal widoki (rozwiń odwołanie do widoku jako makro)

Na tej samej stronie jest napisane:

W terminologii optymalizatora MySQL każde zapytanie jest zestawem złączeń. Pojęcie złączenia jest tu stosowane szerzej niż w poleceniach SQL. Zapytanie dotyczące tylko jednej tabeli jest połączeniem zdegenerowanym. Podczas gdy normalnie nie myślimy o czytaniu rekordów z jednej tabeli jako złączenia, te same struktury i algorytmy używane w konwencjonalnych złączeniach działają idealnie, aby rozwiązać zapytanie z tylko jedną tabelą.

EPILOG

Ze względu na obecne klucze, ilość danych i wyrażenie zapytania, połączenia MySQL mogą czasami robić rzeczy dla naszego własnego dobra (lub wrócić do nas) i dawać wyniki, których się nie spodziewaliśmy i których nie możemy szybko wyjaśnić.

O tym dziwactwie pisałem już wcześniej

ponieważ Optymalizator zapytań MySQL może spowodować odrzucenie niektórych kluczy podczas oceny zapytania.

Komentarz @ Phila pomaga mi zobaczyć, jak opublikować tę odpowiedź (+1 za komentarz @ Phila)

Komentarz @ ypercube (+1 również dla tego) jest kompaktową wersją mojego postu, ponieważ Optymalizator zapytań MySQL jest prymitywny. Niestety musi tak być, ponieważ dotyczy zewnętrznych silników pamięci masowej.

WNIOSEK

Jeśli chodzi o twoje pytanie, Optymalizator zapytań MySQL określałby wskaźniki wydajności każdego zapytania po jego zakończeniu

  • liczenie wierszy
  • wybieranie kluczy
  • masowanie przerywanych zestawów wyników
  • O tak, robię rzeczywiste DOŁĄCZ

Prawdopodobnie musiałbyś wymusić kolejność wykonywania przez przepisanie (refaktoryzację) zapytania

Oto pierwsze zadane przez Ciebie zapytanie

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

Spróbuj przepisać go, aby najpierw ocenić GDZIE

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

To zdecydowanie zmieni plan EXPLAIN. Może dawać lepsze lub gorsze wyniki.

Kiedyś odpowiedziałem na pytanie w StackOverflow, w którym zastosowałem tę technikę. EXPLAIN był przerażający, ale występ był dynamitem. Działa to tylko z powodu obecności poprawnych indeksów i zastosowania LIMIT w podzapytaniu .

Podobnie jak w przypadku cen akcji, jeśli chodzi o zapytania i próby ich wyrażenia, obowiązują ograniczenia, wyniki mogą się różnić, a wyniki w przeszłości nie wskazują przyszłych wyników.

RolandoMySQLDBA
źródło
2
+1 za szczegółowe informacje specyficzne dla MySQL, a zwłaszcza za nakłonienie mnie do zrozumienia różnicy między „Epilogiem” a „Wnioskiem”!
BellevueBob,
W moim poście Epilog jest wnioskiem cząstkowym.
RolandoMySQLDBA
6
@Rolando: Możesz dodać następstwo dotyczące ulepszeń optymalizatorów w najnowszych wersjach MariaDB (5.3 i 5.5) oraz w niedawno wydanej głównej wersji MySQL (5.6). Co może sprawić, że niektóre przepisywanie nie będzie konieczne.
ypercubeᵀᴹ
1

W przypadku Oracle, ponieważ mySQL ma długi opis, mamy 2 ogólne sposoby wykorzystania optymalizatora.

Pierwszą z nich jest optymalizacja oparta na regułach (lub RBO). Oracle ma 15 wbudowanych reguł, które każde analizowane zapytanie próbuje wykonać w ustalonej kolejności. Jeśli nie będzie w stanie wygenerować zoptymalizowanego zapytania z reguły 1, przejdzie do reguły 2 i dalej, aż osiągnie regułę 15.

Aby uzyskać więcej informacji: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

Wpływają one na jądra Oracle RDBMS od wersji 11.1 i niższych, które nie zostały przekonwertowane na Optymalizator kosztowy (inaczej CBO). Oracle 11.2 i nowsze wersje wymagają optymalizatora CBO, ale mogą zmusić określone identyfikatory Sql do optymalizacji w starej metodzie RBO, jeśli użytkownik tego chce.

CBO dla Oracle 11.1+ zamiast tego tworzy kilka planów wykonania dla tego samego identyfikatora SQL i wykonuje ten z najmniejszym ogólnie oczekiwanym kosztem. Wykorzystuje wiele logiki z RBO, ale analizuje statystyki tabeli, aby stworzyć dynamiczne koszty planu wykonania dla każdej operacji, którą DB musi zrobić, aby dostarczyć użytkownikowi końcowemu swoje dane. Wykonywanie pełnych skanów tabel na bardzo dużych stołach jest naprawdę kosztowne; wykonywanie pełnego skanowania tabeli na stole z 10 wierszami jest tanie. W RBO zostały one uznane za równe operacje.

Aby uzyskać więcej informacji: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

W przypadku konkretnego przykładu zapytania: Oracle prawdopodobnie przeanalizuje informacje w celu stworzenia różnych planów wykonania, a zatem jeden będzie lepszy technicznie od drugiego. Może to jednak być minimalna różnica. Patrząc na to, zarówno Oracle RBO, jak i CBO chcieliby zapytać o 1 więcej, ponieważ wykonuje on na sprzężeniu na mniejszych warunkach, a następnie odfiltrowuje określoną kolumnę z tabeli tymczasowej, którą utworzył ze sprzężenia.

JB-Learner
źródło
1

Jeśli masz dwa zapytania i uważasz, że są one równoważne, mogą wystąpić następujące zdarzenia:

  1. Oba zapytania mają ten sam plan wykonania. W porządku i tego właśnie oczekujemy. Miejmy nadzieję, że jest to optymalny plan wykonania dla zapytania.
  2. istnieją różne plany wykonania. Mamy tutaj dwie podklasy.

    2.1 Zapytania mają różne plany wykonania, ale oba plany działają równie dobrze. To też jest w porządku. Nie ma potrzeby, aby dla równoważnych zapytań musiał zostać wygenerowany ten sam plan. Ale wydajność powinna być równa. I znów mamy nadzieję, że jest to najlepsze z możliwych.

    2.2 Zapytania mają różne plany wykonania, a jeden plan jest lepszy od drugiego. Ponownie mamy podklasy:

    2.2.1 Plany są różne, ponieważ zapytania nie są równoważne. Więc dokładnie sprawdź, czy są naprawdę równoważne. W twoim przypadku są one naprawdę równoważne.

    2.2.2 Plany są różne, ale zapytania są równoważne. Oznacza to, że optymalizator nie jest wystarczająco dojrzały. W idealnym świecie z idealnymi optymalizatorami tak się nie powinno stać. Tak, to zależy od platformy i musisz przestudiować dokumenty dotyczące konkretnej platformy, aby dowiedzieć się, dlaczego tak się dzieje.

    2.2.3 Plany są różne, zapytania są równoważne, oprogramowanie bazy danych ma błąd.

cud173
źródło