Przyłączenie wewnętrzne vs Gdzie

257

Czy istnieje różnica w wydajności (w wyroczni) między

Select * from Table1 T1 
Inner Join Table2 T2 On T1.ID = T2.ID

I

Select * from Table1 T1, Table2 T2 
Where T1.ID = T2.ID

?

juan
źródło
1
dla
przypomnienia
12
@BlackTigerX: Różne wyniki? Czy w grę wchodziły jakieś połączenia zewnętrzne? Ponieważ nie widzę, jak wyglądałyby różne wyniki między inner join ... onumieszczeniem równoważnych kryteriów łączenia w whereklauzuli.
Shannon Severance
w starej wersji bazy danych Oracle nie istniejejoin
MajidTaheri
2
@MajidTaheri: ile masz lat wersji Oracle, o której mówisz? Każda wersja obsługiwana przez Oracle obsługuje notację JOIN.
Jonathan Leffler
Zwróć uwagę na ogólne odpowiedzi lub najlepsze praktyki oparte na trywialnych przypadkach. Chciałbym zobaczyć „ponowne dopasowanie” z bardziej złożonymi klauzulami obejmującymi wiele warunków AND. Przynajmniej z SQL Server istnieje punkt podziału.
crokusek

Odpowiedzi:

195

Nie! Ten sam plan wykonania, spójrz na te dwie tabele:

CREATE TABLE table1 (
  id INT,
  name VARCHAR(20)
);

CREATE TABLE table2 (
  id INT,
  name VARCHAR(20)
);

Plan wykonania zapytania przy użyciu sprzężenia wewnętrznego:

-- with inner join

EXPLAIN PLAN FOR
SELECT * FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.id;

SELECT *
FROM TABLE (DBMS_XPLAN.DISPLAY);

-- 0 select statement
-- 1 hash join (access("T1"."ID"="T2"."ID"))
-- 2 table access full table1
-- 3 table access full table2

I plan wykonania zapytania przy użyciu klauzuli WHERE.

-- with where clause

EXPLAIN PLAN FOR
SELECT * FROM table1 t1, table2 t2
WHERE t1.id = t2.id;

SELECT *
FROM TABLE (DBMS_XPLAN.DISPLAY);

-- 0 select statement
-- 1 hash join (access("T1"."ID"="T2"."ID"))
-- 2 table access full table1
-- 3 table access full table2
kiewic
źródło
4
Naprawdę chciałbym sprawdzić, czy jest jakaś oficjalna dokumentacja Oracle na ten temat
4 Leave Cover
68

Jeśli optymalizator zapytań dobrze wykonuje swoje zadanie, nie powinno być różnicy między tymi zapytaniami. Są to tylko dwa sposoby określenia tego samego pożądanego rezultatu.

Craig Trader
źródło
22
Tak, wydajność powinna być taka sama. Ale WYBIERZ * Z Tabeli 1, Tabeli 2 GDZIE ... składnia jest ZŁA!
Joel Coehoorn
2
O wiele łatwiej jest mi zrozumieć POŁĄCZENIA WEWNĘTRZNE niż składnia SQL-92. Twój przebieg może się różnić.
Craig Trader
25
Uważam, że składnia GDZIE jest łatwiejsza do odczytania niż INNER JION - wydaje mi się, że jest jak Vegemite. Większość ludzi na świecie prawdopodobnie uważa to za obrzydliwe, ale dzieci, które je wychowały, uwielbiają to.
ScottCher,
3
Vegemite jest naprawdę paskudny, ale z drugiej strony uwielbiam złom. Domyśl.
StingyJack
2
@Darryl Myślę, że JOINsą łatwiejsze do odczytania, ponieważ warunek dołączenia do tabel jest zdefiniowany natychmiast, zamiast „gdzieś” w WHEREklauzuli. Wolę zarezerwować WHEREklauzulę ograniczającą zestaw danych (np. WHERE DATE > (SYSDATE - 1)) Zamiast definiować również, w jaki sposób tabele odnoszą się do siebie (np WHERE T1.ID = T2.ID.). W przypadku małej tabeli, takiej jak przykład, nie ma znaczenia, ale w przypadku dużych zapytań obejmujących kilka tabel i kilka warunków myślę, że znacznie ułatwia zrozumienie zapytania.
ImaginaryHuman072889
61

Powinny być dokładnie takie same. Jednak jako praktykę kodowania wolałbym zobaczyć Join. Wyraźnie wyraża twoje zamiary,

Nescio
źródło
8
Zgadzam się. Zwłaszcza jeśli dołączasz do wielu tabel, o wiele łatwiej jest parsować instrukcję select, jeśli wykonujesz jawne połączenia.
Paul Morie
13
W rzeczy samej. Połączenia reprezentują semantyczny związek między dwoma zestawami danych, ale gdzie sugeruje zestaw filtrowany. +1
EightyOne Unite
26

Użycie JOINsprawia, że ​​kod jest łatwiejszy do odczytania, ponieważ jest oczywisty.

Nie ma różnicy prędkości ( właśnie ją przetestowałem ), a plan wykonania jest taki sam.

użytkownik21241
źródło
Dziękuję Ci. szukałem kompresji prędkości między tymi dwiema metodami.
Farhad Navayazdan
14

Nie wiem o Oracle, ale wiem, że stara składnia jest przestarzała w SQL Server i ostatecznie zniknie. Zanim użyłem tej starej składni w nowym zapytaniu, sprawdzę, co Oracle zamierza z tym zrobić.

Wolę nowszą składnię niż mieszanie kryteriów łączenia z innymi potrzebnymi tam, gdzie warunki. W nowszej składni jest o wiele bardziej jasne, co tworzy sprzężenie i jakie inne warunki są stosowane. Nie jest to naprawdę duży problem w przypadku takiego krótkiego zapytania, ale staje się znacznie bardziej skomplikowany, gdy masz bardziej złożone zapytanie. Ponieważ ludzie uczą się podstawowych zapytań, wolę, aby ludzie uczyli się używać składni łączenia, zanim będą potrzebować jej w złożonym zapytaniu.

I znowu nie znam konkretnie Oracle, ale wiem, że wersja lewego złączenia w starym stylu SQL Server jest wadliwa nawet w SQL Server 2000 i daje niespójne wyniki (czasami lewe złączenie, czasem łączenie krzyżowe), więc nigdy nie powinno być używany. Mam nadzieję, że Oracle nie cierpi z tego samego powodu, ale z pewnością lewe i prawe złączenia mogą być trudniejsze do prawidłowego wyrażenia w starej składni.

Co więcej, to moje doświadczenie (i oczywiście jest to wyłącznie osobista opinia, możesz mieć różne doświadczenia), że programiści używający standardowych złączeń ANSII zwykle lepiej rozumieją, czym jest łączenie i co to znaczy w kontekście uzyskiwania dane z bazy danych. Wierzę, że większość osób z dobrą znajomością bazy danych ma tendencję do pisania bardziej złożonych zapytań, a te wydają mi się o wiele łatwiejsze w obsłudze przy użyciu standardu ANSII niż w starym stylu.

HLGEM
źródło
1
Brat Amen. Precz ze DOŁĄCZONYMI !!
ScottCher,
14

[Za punkt bonusowy ...]

Korzystanie ze składni JOIN pozwala łatwiej komentować złączenie, ponieważ jest ono zawarte w jednym wierszu. To może być przydatne, jeśli debugujesz złożone zapytanie

Jak wszyscy inni mówią, są funkcjonalnie takie same, jednak JOIN jest bardziej wyraźny od deklaracji intencji. Dlatego może w niektórych przypadkach pomóc optymalizatorowi zapytań w aktualnych wersjach Oracle (nie mam pojęcia, czy tak jest), może pomóc optymalizatorowi zapytań w przyszłych wersjach Oracle (nikt nie ma pojęcia) lub może pomóc, jeśli zmieniasz dostawcę bazy danych.

Chris Gill
źródło
2
Lub ... łatwo zmień ŁĄCZENIA WEWNĘTRZNE na POŁĄCZENIA LEWE, dzięki czemu zobaczysz, które sprzężenie powoduje pominięcie oczekiwanych wierszy. Robię to, ponieważ wykonuję całe zapytanie naraz. Jeśli skomentujesz ŁĄCZENIA WEWNĘTRZNE, będziesz musiał przeprowadzić proces eliminacji. To trwa dłużej. Ale +1 dla Ciebie, ponieważ jest to jeden z moich ulubionych powodów DOŁĄCZENIA WEWNĘTRZNEGO oprócz czytelności!
Matthew McPeak
13

Są logicznie identyczne, ale we wcześniejszych wersjach Oracle, które przyjęły składnię ANSI, często występowały z nią błędy w bardziej złożonych przypadkach, więc czasami napotykasz opór ze strony programistów Oracle podczas korzystania z niej.

David Aldridge
źródło
Wcześniejsze wersje Oracle miały z tym błędy? Jak wcześnie? Jakie wersje?
ScottCher,
Metalink ma detale ... wyskakują wszędzie.
David Aldridge
7

Wydajność powinna być identyczna, ale sugerowałbym użycie wersji złączenia ze względu na lepszą przejrzystość w przypadku złączeń zewnętrznych.

Za pomocą wersji złączonej można również uniknąć niezamierzonych produktów kartezjańskich.

Trzecim efektem jest łatwiejszy do odczytania SQL z prostszym warunkiem GDZIE.

stili
źródło
Naprawdę uważam, że kluczem są niezamierzone skutki, gdy kryteria są niejednoznaczne. Jeśli określisz rodzaj łączenia, wiesz dokładnie, co otrzymujesz. Przekonałem się, że różne bazy danych, a nawet różne wersje tej samej platformy bazy danych będą obsługiwały wartości zerowe w różny sposób w domniemanym złączeniu. Kiedy określasz lewy / prawy wewnętrzny / zewnętrzny, poświęcasz czas na zastanowienie się, które z nich jest poprawne. Kiedy używasz niejednoznacznej metody, zakładasz, że działa ona tak, jak chcesz / zamierzasz.
Steve Kallestad,
6

Nie zapominaj, że w Oracle, pod warunkiem, że kluczowe atrybuty łączenia mają taką samą nazwę w obu tabelach, możesz także zapisać to jako:

select *
from Table1 inner join Table2 using (ID);

Oczywiście ma to również ten sam plan zapytań.

cheduardo
źródło
I rollbacked wydanie ponieważ poprzednia wersja zmieniła sens odpowiedzi
juan
5

W scenariuszu, w którym tabele są w 3 normalnej formie, połączenia między tabelami nie powinny się zmieniać. Dołącz do KLIENTÓW, a PŁATNOŚCI powinny zawsze pozostać takie same.

Powinniśmy jednak odróżniać sprzężenia od filtrów . Połączenia dotyczą relacji, a filtry dotyczą partycjonowania całości.

Niektórzy autorzy, odnosząc się do standardu (np. Jim Melton; Alan R. Simon (1993). Zrozumienie nowego SQL: kompletny przewodnik. Morgan Kaufmann. Str. 11–12. ISBN 978-1-55860-245-8.) , napisał o korzyściach z zastosowania składni JOIN w tabelach oddzielonych przecinkami w klauzuli FROM.

Całkowicie zgadzam się z tym punktem widzenia.

Istnieje kilka sposobów pisania SQL i osiągania tych samych rezultatów, ale dla wielu osób pracujących w zespole czytelność kodu źródłowego jest ważnym aspektem, a na pewno oddzielenie, w jaki sposób tabele odnoszą się do siebie od określonych filtrów, było dużym krokiem w kierunku wyjaśnienia źródła kod.

abrittaf
źródło
Łączenie wewnętrzne oznacza łączenie krzyżowe gdzie. Przecinek jest łączeniem krzyżowym z niższym priorytetem niż łączenie słów kluczowych. Włączone vs „filtr” nie ma znaczenia dla łączenia wewnętrznego. NF nie mają znaczenia dla zapytań. Nic w standardzie nie promuje łączenia słów kluczowych przecinkiem. Trywialne optymalizacje traktują podobnie i gdziekolwiek. Ta odpowiedź to mnóstwo nieporozumień.
philipxy
1) Wydaje mi się, że @philipxy próbuje powiedzieć „W klauzulach FROM tabele oddzielone przecinkiem mają takie samo znaczenie, jak tabele CROSS JOINed”. Zgadzam się z tym. Oczywiście możesz trzymać się starej składni, która może współistnieć z klauzulami JOIN. Optymalizatory RDBMS doskonale zrozumieją oba przypadki jako takie same (w przypadku, gdy są one oczywiście równoważne) i opracują ten sam plan.
abrittaf
4

W PostgreSQL zdecydowanie nie ma różnicy - oba odpowiadają temu samemu planowi zapytań. Jestem 99% pewien, że dotyczy to również Oracle.

Nick Johnson
źródło
2

Oba są złączeniami wewnętrznymi, które robią to samo, po prostu używa się nowszej składni ANSI.

Bob Gettys
źródło
2

Funkcjonalnie są takie same, jak powiedziano. Zgadzam się jednak, że wykonanie sprzężenia lepiej opisuje dokładnie to, co chcesz zrobić. Wiele razy myślałem, że wiem, jak chciałem zapytać o coś, dopóki nie zacząłem łączyć się i zdałem sobie sprawę, że chcę wykonać inne zapytanie niż oryginalne w mojej głowie.

MattC
źródło
1

Prawdą jest, że funkcjonalnie oba zapytania powinny być przetwarzane w ten sam sposób. Jednak doświadczenie pokazuje, że jeśli wybierasz spośród widoków, które używają nowej składni złączenia, ważne jest, aby również ustrukturyzować swoje zapytania. Optymalizator Oracle może się pomylić, jeśli widok używa instrukcji „dołącz”, ale zapytanie uzyskujące dostęp do widoku używa tradycyjnej metody łączenia w klauzuli „gdzie”.

JoshL
źródło
To bardziej problem z widokami niż z łączeniami.
nieistniejący
0

Chociaż tożsamość dwóch zapytań wydaje się oczywista, czasem zdarzają się dziwne rzeczy. Przyszedłem do zapytania, które ma inne plany wykonania podczas przenoszenia predykatu łączenia z JOIN na WHERE w Oracle 10g (bo plan WHERE jest lepszy), ale nie mogę odtworzyć tego problemu w uproszczonych tabelach i danych. Myślę, że to zależy od moich danych i statystyk. Optymalizator jest dość złożonym modułem i czasami zachowuje się magicznie.

Właśnie dlatego nie możemy ogólnie odpowiedzieć na to pytanie, ponieważ zależy to od wewnętrznych elementów DB. Ale powinniśmy wiedzieć, że odpowiedzią musi być „ brak różnic ”.

greatvovan
źródło
0

Miałem dzisiaj tę zagadkę, kiedy sprawdziłem limit czasu produkcji jednego z naszych sp, zmieniłem wewnętrzne sprzężenie w tabeli zbudowanej z kanału XML na klauzulę „gdzie” zamiast tego .... średni czas wykonania wynosi teraz 80 ms ponad 1000 wykonań, podczas gdy zanim średni exec wynosił 2,2 sekundy ... główną różnicą w planie wykonania jest zniknięcie wyszukiwania klucza ... Komunikat, że nie będziesz wiedział, dopóki nie przetestujesz przy użyciu obu metod.

Twoje zdrowie.

trbullet81
źródło
0

Jak powiedział kiewik, plan wykonania jest taki sam.

Instrukcja JOIN jest tylko łatwiejsza do odczytania, dzięki czemu łatwiej nie zapomnieć o warunku WŁĄCZENIA i uzyskać produkt kartezjański. Błędy te mogą być dość trudne do wykrycia w długich zapytaniach przy użyciu wielu złączeń typu: SELECT * FROM t1, t2 GDZIE t1.id = t2.some_field.

Jeśli zapomnisz tylko jeden warunek łączenia, wykonanie zapytania spowoduje zwrócenie zbyt wielu rekordów ... naprawdę zbyt wielu. Niektórzy ludzie używają DISTINCT, aby załatać zapytanie, ale nadal jest bardzo długi do wykonania.

Właśnie dlatego używanie instrukcji JOIN jest z pewnością najlepszą praktyką: lepszą konserwowalność i lepszą czytelność.

Co więcej, jeśli dobrze pamiętam, JOIN jest zoptymalizowany pod kątem wykorzystania pamięci.

ROQUEFORT François
źródło
0

Mam uzupełnienie tej dobrej odpowiedzi :

To właśnie jest odpowiednio zdefiniowane jako SQL92 i SQL89, nie ma między nimi różnicy wydajności, chociaż można pominąć słowo INNER (użycie tylko JOIN jest wystarczająco jasne, a w najprostszym zapytaniu zapisujesz 5 uderzeń klawiatury teraz wyobraź sobie, ile uderzeń jest w dużych te).

Ivanzinho
źródło