INNER JOIN on vs WHERE clause

Dla uproszczenia, Załóżmy, że wszystkie istotne pola to NOT NULL.

Możesz zrobić:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1, table2
WHERE
    table1.foreignkey = table2.primarykey
    AND (some other conditions)

Albo:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1 INNER JOIN table2
    ON table1.foreignkey = table2.primarykey
WHERE
    (some other conditions)
Czy te dwa działają w ten sam sposób w MySQL?
Author: Uwe Keim, 2009-06-19

10 answers

INNER JOIN jest składnią ANSI, której powinieneś używać.

Jest ogólnie uważany za bardziej czytelny, zwłaszcza gdy łączysz wiele tabel.

Może być również łatwo zastąpiony OUTER JOIN, gdy zajdzie taka potrzeba.

Składnia WHERE jest bardziej zorientowana na model relacyjny.

Wynik dwóch tabel JOINed jest iloczynem kartezjańskim tabel, do których stosuje się filtr, który wybiera tylko te wiersze z dopasowanymi kolumnami łączącymi.

Łatwiej to zobaczyć z składnia WHERE.

Jak dla Twojego przykładu, w MySQL (i ogólnie w SQL) te dwa zapytania są synonimami.

Zauważ również, że MySQL ma również klauzulę STRAIGHT_JOIN.

Używając tej klauzuli, możesz kontrolować kolejność JOIN: która tabela jest skanowana w zewnętrznej pętli, a która w wewnętrznej.

Nie można tego kontrolować w MySQL używając składni WHERE.

 622
Author: Quassnoi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-19 16:28:17

Inni zwrócili uwagę, że połączenie wewnętrzne pomaga czytelności człowieka, i to jest najwyższy priorytet; zgadzam się. Spróbuję wyjaśnić Dlaczego składnia join jest bardziej czytelna.

Podstawowe zapytanie SELECT to:

SELECT stuff
FROM tables
WHERE conditions

Klauzula SELECT mówi nam Co otrzymujemy; klauzula FROM mówi nam skąd otrzymujemy to, a klauzula WHERE mówi nam które otrzymujemy.

JOIN to stwierdzenie o tabelach, jak są one związane razem (koncepcyjnie, właściwie, w jedną tabelę). Wszelkie elementy zapytań, które kontrolują tabele - skąd pobieramy rzeczy-semantycznie należą do klauzuli FROM (i oczywiście tam trafiają elementy JOIN). Umieszczenie elementów łączących w klauzuli WHERE łączy which i where-from; dlatego preferowana jest składnia JOIN.

 149
Author: Carl Manaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:30:59

stosowanie instrukcji warunkowych w ON / WHERE

Tutaj wyjaśniłem o logicznych etapach przetwarzania zapytań.


[[4]} odniesienie: Inside Microsoft® SQL Server™ 2005 T-SQL Querying
Wydawca: Microsoft Press
Pub Date: Marzec 07, 2006
Drukuj ISBN-10: 0-7356-2313-9
Drukuj ISBN-13: 978-0-7356-2313-2
Strony: 640

Inside Microsoft® SQL Server™ 2005 T-SQL Querying

(8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
(1)  FROM <left_table>
(3)       <join_type> JOIN <right_table>
(2)       ON <join_condition>
(4)  WHERE <where_condition>
(5)  GROUP BY <group_by_list>
(6)  WITH {CUBE | ROLLUP}
(7)  HAVING <having_condition>
(10) ORDER BY <order_by_list>

Pierwszy zauważalny aspektem SQL, który różni się od innych języków programowania, jest kolejność, w jakiej kod jest przetwarzany. W większości języków programowania kod jest przetwarzany w kolejności, w jakiej został napisany. W SQL pierwszą przetwarzaną klauzulą jest klauzula FROM, podczas gdy klauzula SELECT, która pojawia się jako pierwsza, jest przetwarzana prawie jako ostatnia.

Każdy krok generuje wirtualną tabelę, która jest używana jako wejście do następnego kroku. Te wirtualne tabele nie są dostępne dla dzwoniącego (klienta wniosek lub zapytanie zewnętrzne). Tylko tabela wygenerowana przez ostatni krok jest zwracana do wywołującego. Jeśli pewna klauzula nie jest określona w zapytaniu, odpowiedni krok jest po prostu pomijany.

Krótki opis faz Przetwarzania zapytań logicznych

Nie martw się zbytnio, jeśli opis kroków nie wydaje się na razie mieć większego sensu. Są one dostarczane jako punkt odniesienia. Sekcje, które pojawią się po przykładzie scenariusza, obejmą znacznie więcej kroków szczegóły.

  1. FROM: pomiędzy dwoma pierwszymi tabelami w klauzuli FROM wykonywany jest iloczyn kartezjański (Cross join), w wyniku czego generowana jest wirtualna tabela VT1.

  2. ON: filtr ON jest stosowany do VT1. Tylko wiersze, dla których <join_condition> jest prawdziwe, są wstawiane do VT2.

  3. Zewnętrzne (join): jeśli podano zewnętrzne połączenie (w przeciwieństwie do połączenia krzyżowego lub wewnętrznego), wiersze z zachowanej tabeli lub tabel, dla których nie znaleziono dopasowania, są dodawane do wiersze z VT2 jako wiersze zewnętrzne, generujące VT3. Jeśli w klauzuli FROM pojawią się więcej niż dwie tabele, kroki od 1 do 3 są stosowane wielokrotnie między wynikiem ostatniego połączenia a następną tabelą w klauzuli FROM, aż wszystkie tabele zostaną przetworzone.

  4. Gdzie: filtr WHERE jest stosowany do VT3. Tylko wiersze, dla których <where_condition> jest prawdziwe, są wstawiane do VT4.

  5. GROUP BY: wiersze z VT4 są ułożone w grupy na podstawie listy kolumn określonej w grupie przez klauzula. VT5 jest generowany.

  6. CUBE / ROLLUP: supergrupy (grupy grup) są dodawane do wierszy z VT5, generując VT6.

  7. Posiadanie: filtr HAVING jest stosowany do VT6. Tylko grupy, dla których <having_condition> jest prawdziwe są wstawiane do VT7.

  8. SELECT: lista SELECT jest przetwarzana, generując VT8.

  9. DISTINCT: zduplikowane wiersze są usuwane z VT8. Vt9 jest generowany.

  10. Uporządkuj według: wiersze z VT9 są sortowane zgodnie z listą kolumn określoną w klauzuli ORDER BY. Generowany jest kursor (VC10).

  11. Góra: określona liczba lub procent wierszy jest wybierany od początku VC10. Tabela VT11 jest generowana i zwracana do wywołującego.



Dlatego (INNER JOIN) ON filtruje dane (Liczba danych VT zostanie tutaj zmniejszona) przed zastosowaniem klauzuli WHERE. Kolejne warunki przyłączenia zostaną wykonane z filtrowanym danych, które poprawiają wydajność. Po tym tylko warunek gdzie będzie stosować warunki filtra.

(stosowanie poleceń warunkowych w ON / WHERE nie będzie miało większego znaczenia w kilku przypadkach. Zależy to od liczby połączonych tabel i liczby wierszy dostępnych w każdej z tabel)

 115
Author: rafidheen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-28 18:38:37

Domyślna składnia ANSI join jest starsza, mniej oczywista i niezalecana.

Ponadto algebra relacyjna umożliwia wymienność predykatów w klauzuli WHERE i INNER JOIN, więc nawet zapytania INNER JOIN z klauzulami WHERE mogą mieć predykaty przestawione przez optymalizator.

Zalecam pisanie zapytań w jak najbardziej czytelny sposób.

Czasami obejmuje to uczynienie INNER JOIN stosunkowo "niekompletnym" i umieszczenie niektórych kryteriów w WHERE po prostu, aby listy kryteriów filtrowania były łatwiejsze do utrzymania.

Na przykład zamiast:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Napisz:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1
Ale to oczywiście zależy.
 55
Author: Cade Roux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:23:45

Połączenia niejawne (czyli to, co jest znane jako pierwsze zapytanie) stają się znacznie bardziej mylące, trudne do odczytania i trudne do utrzymania, gdy trzeba zacząć dodawać więcej tabel do zapytania. Wyobraź sobie, że robisz to samo zapytanie i rodzaj połączenia na czterech lub pięciu różnych tabelach ... to koszmar.

Użycie jawnego łącznika (twój drugi przykład) jest o wiele bardziej czytelne i łatwe w utrzymaniu.

 26
Author: matt b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:19:14

Zwrócę również uwagę, że używanie starszej składni jest bardziej narażone na błędy. Jeśli użyjesz łączników wewnętrznych bez klauzuli ON, otrzymasz błąd składni. Jeśli użyjesz starszej składni i zapomnisz jednego z warunków join w klauzuli where, otrzymasz łącze krzyżowe. Programiści często naprawiają to, dodając osobne słowo kluczowe (zamiast naprawiać join, ponieważ nadal nie zdają sobie sprawy, że samo join jest zepsute), co może wydawać się rozwiązaniem problemu, ale spowolni zapytanie znacznie.

DODATKOWO dla utrzymania jeśli masz łącze krzyżowe w starej składni, skąd opiekun będzie wiedział, czy chcesz je mieć (są sytuacje, w których potrzebne są łącza krzyżowe) lub czy to był wypadek, który powinien zostać naprawiony?

Pozwól, że wskażę ci to pytanie, aby zobaczyć, dlaczego domyślna składnia jest zła, jeśli używasz lewych łączników. Sybase* = do standardu Ansi z 2 różnymi tablicami zewnętrznymi dla tej samej tabeli wewnętrznej

Plus (personal rant here), standard używanie jawnych łączy ma ponad 20 lat, co oznacza, że składnia implicit join jest przestarzała przez te 20 lat. Czy napisałbyś kod aplikacji używając przestarzałej od 20 lat składni? Dlaczego chcesz napisać kod bazy danych, który jest?

 22
Author: HLGEM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:50

Mają inne znaczenie czytelne dla człowieka.

Jednak, w zależności od optymalizatora zapytań, mogą one mieć takie samo znaczenie dla maszyny.

Należy zawsze kodować, aby był czytelny.

To znaczy, jeśli jest to relacja wbudowana, użyj jawnego join. jeśli dopasowujesz słabo Powiązane Dane, użyj klauzuli where.

 12
Author: John Gietzen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-15 22:04:49

Standard SQL:2003 zmienił niektóre reguły pierwszeństwa, więc deklaracja JOIN ma pierwszeństwo przed połączeniem" przecinkiem". Może to rzeczywiście zmienić wyniki zapytania w zależności od sposobu konfiguracji. Powoduje to pewne problemy dla niektórych osób, gdy MySQL 5.0.12 przeszedł na zgodność ze standardem.

Więc w twoim przykładzie, Twoje zapytania będą działać tak samo. Ale jeśli dodasz trzecią tabelę: Wybierz ... Od table1, table2 dołącz do table3 na ... Gdzie..

Przed MySQL 5.0.12, table1 i najpierw dołączy się table2, potem table3. Teraz (5.0.12 i włączone), table2 i table3 są najpierw połączone, a następnie table1. To nie zawsze zmienia wyniki, ale może i może nawet nie zdawać sobie z tego sprawy.

Nigdy już nie używam składni "przecinek", wybierając drugi przykład. I tak jest o wiele bardziej czytelny, warunki przyłączenia są z połączeniami, a nie rozdzielone w oddzielną sekcję zapytań.

 10
Author: Brent Baisley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 17:28:56

Wiem, że mówisz o MySQL, ale w każdym razie: W Oracle 9 połączenia jawne i niejawne generowałyby różne plany wykonania. AFAIK, który został rozwiązany w Oracle 10+: nie ma już takiej różnicy.

 4
Author: João Marcus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 17:03:42

Składnia ANSI join jest zdecydowanie bardziej przenośna.

Przechodzę przez aktualizację Microsoft SQL Server, i chciałbym również wspomnieć, że składnia = * i * = dla zewnętrznych połączeń w SQL Server nie jest obsługiwana (bez trybu zgodności) dla 2005 SQL server i Później.

 1
Author: Benzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-19 16:50:12