2014-07-21 31 views
9

W this candidate answer jest on twierdził, że jest lepiej niż JOINLEFT JOIN w pewnych okolicznościach obejmujących kilka WHERE klauzule ponieważ nie mylić planera zapytania i nie jest „bez sensu”. Twierdzenie/założenie jest takie, że powinno to być oczywiste dla każdego.Wyjaśnij JOIN vs. LEFT JOIN i gdzie sugestia wydajność warunek bardziej szczegółowo

Proszę wyjaśnić dalej lub podać link (y) do dalszego czytania.

+0

Lepiej? Służą one do innego celu. JOIN jest złączeniem wewnętrznym, LEFT JOIN jest złączem zewnętrznym (to samo co LEFT OUTER JOIN). W zależności od twoich intencji użyjesz sprzężenia zewnętrznego lub wewnętrznego. Klauzuli WHERE nie należy używać do warunków łączenia. Należy go stosować do innych kryteriów; to znaczy. filtracja. –

+0

Przeczytałem tam odpowiedź jako "Ponieważ LEWY DOŁĄCZ (z WHERE) jest * efektywnie * INNER JOIN, użyj zamiast tego INNER JOIN". Nie jestem pewien, jak "mylące" jest dla [konkretnego] programu do planowania zapytań, ale jest on mniejszy niż idealny dla człowieka [czytaj: moje] zużycie, IMOHO. (To samo można powiedzieć o użyciu CROSS JOIN, gdy wystarczą INNER, np.) – user2864740

+0

Lewe sprzężenie z klauzulą ​​where, KTÓRA UŻYWA TABELĘ POŁĄCZONĄ ZEWNĘTRZNIE, jest faktycznie połączeniem wewnętrznym. Jednak jeśli klauzula where nie używa zewnętrznego połączonego stołu, nie, to nieprawda. –

Odpowiedz

17

Rozważmy następujący przykład. Mamy dwie tabele, DEPARTAMENTY i PRACOWNICY.

Niektóre działy nie mają jeszcze pracowników.

To zapytanie wykorzystuje sprzężenie wewnętrzne, które znajdzie pracownika działu 999 pracuje w, jeśli w ogóle, w przeciwnym razie nie pokazuje nic (nawet pracownika lub jego nazwa):

select a.department_id, a.department_desc, b.employee_id, b.employee_name 
    from departments a 
    join employees b 
    on a.department_id = b.department_id 
where b.employee_id = '999' 

Następny kwerendy używa łączenie zewnętrzne (po lewej stronie między działami i pracownikami) i znajduje dział, w którym pracuje 999 pracownik. Jednak również nie będzie pokazywał identyfikatora pracownika ani jego nazwiska, jeśli nie działają oni w żadnym departamencie. Wynika to z faktu, że zewnętrzna połączona tabela jest używana w klauzuli WHERE. Jeśli nie ma odpowiedniego działu, będzie to wartość pusta (nie 999, mimo że 999 istnieje w przypadku pracowników).

select a.department_id, a.department_desc, b.employee_id, b.employee_name 
    from departments a 
    left join employees b 
    on a.department_id = b.department_id 
where b.employee_id = '999' 

ale za to zapytanie:

select a.department_id, a.department_desc, b.employee_id, b.employee_name 
    from departments a 
    left join employees b 
    on a.department_id = b.department_id 
    and b.employee_id= '999' 

Teraz kryteriów jest w sprawie klauzuli. Więc nawet jeśli ten pracownik pracuje w żadnym departamencie, nadal będzie zwrócony (jego identyfikator i imię). Kolumny działu będą miały wartość null, ale otrzymamy wynik (strona pracownika).

Można by pomyśleć, że nigdy nie będziesz chciał używać zewnętrznego połączonego stołu w klauzuli WHERE, ale niekoniecznie tak jest. Zwykle jest tak z przyczyn opisanych powyżej.

Załóżmy, że chcesz wszystkie działy bez pracowników. Następnie można wykonać następujące czynności, które wykonuje użyć sprzężenia zewnętrznego, a zewnętrzna dołączył tabela jest używana w klauzuli WHERE:

select a.department_id, a.department_desc, b.employee_id 
    from departments a 
    left join employees b 
    on a.department_id = b.department_id 
where b.employee_id is null 

^^ Pokazuje działów bez pracowników.

Powyższy tekst jest prawdopodobnie jedynym słusznym powodem, dla którego chciałbyś użyć tabeli połączonej zewnętrznie w klauzuli WHERE zamiast klauzuli ON (co, jak sądzę, jest twoim pytaniem, różnica między złączeniami wewnętrznym i zewnętrznym jest całkowicie inny temat).

Dobrym sposobem na sprawdzenie jest: Używasz zewnętrznych połączeń, aby zezwalać na wartości zerowe. Dlaczego miałbyś użyć zewnętrznego sprzężenia i powiedzieć, że pole nie powinno być puste i powinno być równe "XYZ"? Jeśli wartość musi mieć wartość "XYZ" (nie ma wartości null), to dlaczego należy nakazać bazie danych zezwolenie na wycofanie wartości null? To tak, jakby powiedzieć jedną rzecz, a później ją przesłonić.

11

Skutecznie, warunki WHERE i warunki JOIN dla [INNER] JOIN są w 100% równoważne w PostgreSQL. (Dobrą praktyką jest używanie jawnych warunków, aby ułatwić sobie czytanie i utrzymywanie zapytań).

To samo dotyczy , a nie true dla LEFT JOIN w połączeniu z warunkiem WHERE na stole po prawej stronie łączenia. Celem LEFT JOIN jest zachowanie wszystkich rzędów po lewej stronie łączenia, niezależnie od dopasowania po prawej stronie. Jeśli nie zostanie znalezione dopasowanie, wiersz zostanie rozszerzony o wartości NULL dla kolumn po prawej stronie. The manual:

LEFT OUTER JOIN

pierwsze sprzężenie wewnętrzne jest wykonane. Następnie dla każdego wiersza w T1, który nie spełnia warunku łączenia z dowolnym wierszem w T2, dodaje się połączony wiersz z wartościami pustymi w kolumnach T2. Zatem połączona tablica zawsze ma co najmniej jeden rząd dla każdego rzędu w T1.

Jeśli następnie zastosować WHERE stan na kolumnach tabel po prawej stronie, to utratę efektu i przymusowo przekonwertować LEFT JOIN pracować jak zwykły JOIN, tylko bardziej kosztownie ze względu na bardziej skomplikowaną planu kwerend.

W zapytaniu z wieloma połączonymi tabelami Postgres (lub dowolny RDBMS) jest trudny do znalezienia najlepszego (lub nawet dobrego) planu zapytań. Liczba teoretycznie możliwych sekwencji do łączenia tabel rośnie czynnikowo (!). Postgres używa do wykonania zadania "Generic Query Optimizer" i istnieje kilka ustawień, które mają na niego wpływ.

Niewyrażenie zapytania z wprowadzającym w błąd LEFT JOIN, jak opisano, utrudnia pracę twórcy zapytań, jest mylące dla czytelników ludzkich i zazwyczaj wskazuje na błędy w logice zapytań.

Wiele problemów związanych z odpowiedzi na wynikające z tego:

Itp.

+0

Jeśli to naprawdę "droższe"? Współcześni planiści zapytań - przyznawani, w większości korzystam z SQL Server - zachwycają mnie. – user2864740

+3

Jaka jest różnica, jeśli jest lub nie jest droższa. Dlaczego używałbyś zewnętrznego sprzężenia z tabelą X, jeśli chcesz powiedzieć, że wartości w tabeli X powinny być czymś (innym niż zero)? Jeśli już, nie rób tego po prostu dlatego, że nie ma sensu. –

+0

@ user2864740: W prostych przypadkach nie ma to większego znaczenia. W skomplikowanych przypadkach utrudnia to zadanie optymalizatora zapytań.Ale jak skomentował Brian: nie rób tego tak czy inaczej. Jest to również bardzo mylące dla ludzkiego czytelnika. –