Czy łączenie jest zoptymalizowane do klauzuli where w czasie wykonywania?

14

Kiedy piszę takie zapytanie ...

select *
from table1 t1
join table2 t2
on t1.id = t2.id

Czy optymalizator SQL, nie będąc pewnym, czy jest to poprawny termin, tłumaczy to na ...

select *
from table1 t1, table2 t2
where t1.id = t2.id

Zasadniczo, czy instrukcja Join w SQL Server jest po prostu łatwiejszym sposobem pisania SQL? Czy jest faktycznie używany w czasie wykonywania?

Edycja: Prawie zawsze i prawie zawsze będę używać składni Join. Jestem po prostu ciekawa, co się dzieje.

Pan Ant
źródło
1
Czy mógłbyś rozwinąć „prawie”? Kiedy miałbyś użyć starej składni i dlaczego?
Aaron Bertrand
2
Jednym z marginesów, w którym ma to znaczenie, jest dodanie (nieaktualne) GROUP BY ALLw
Martin Smith
@MartinSmith czy ktoś GROUP BY ALLcelowo używa ? :-)
Aaron Bertrand
@AaronBertrand - Wątpię! Nie sądzę, że kiedykolwiek widziałem, żeby ktoś z niego korzystał.
Martin Smith

Odpowiedzi:

20

Te upadają wewnętrznie na to samo. Ten pierwszy to ten, który zawsze powinieneś pisać . Co ważniejsze, dlaczego to ma znaczenie? Są identyczne pod względem planu wykonania i wydajności (przy założeniu, że nie zepsujesz tego, co łatwiej zrobić z leniwą składnią w starym stylu).

Oto dowód za pomocą AdventureWorks, że nie ma CROSS JOINi nie filtertrwa dalej.


Wyraźne dołączenie:

wprowadź opis zdjęcia tutaj


Ukryte połączenie:

wprowadź opis zdjęcia tutaj


Spójrz, mamo! Identyczne plany, identyczne wyniki, nigdzie nie widać połączeń krzyżowych ani filtrów.

(Dla jasności ostrzeżenie dla SELECToperatora w obu przypadkach jest niejawną konwersją wpływającą na liczność, w żadnym przypadku nie ma nic wspólnego ze złączeniem.)

Aaron Bertrand
źródło
20

Ściśle mówiąc, istnieją dwie różnice w danych wejściowych do optymalizatora zapytań między dwiema formami:

-- Input tree (ISO-89)
SELECT
    p.Name,
    Total = SUM(inv.Quantity)
FROM 
    Production.Product AS p,
    Production.ProductInventory AS inv
WHERE
    inv.ProductID = p.ProductID
GROUP BY
    p.Name
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);

Drzewo wejściowe ISO-89

-- Input tree (ISO-92)
SELECT
    p.Name,
    Total = SUM(inv.Quantity)
FROM Production.Product AS p
JOIN Production.ProductInventory AS inv ON
    inv.ProductID = p.ProductID
GROUP BY
    p.Name
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);

Drzewo wejściowe ISO-92

Jak widać ONpredykat klauzuli jest ściśle związany z łączeniem przy użyciu nowoczesnej składni. Przy starszej składni istnieje logiczne połączenie krzyżowe, po którym następuje relacyjny wybór (filtr wierszy).

Optymalizator zapytań prawie zawsze zwija relacyjną selekcję do złączenia podczas optymalizacji, co oznacza, że ​​te dwie formy prawdopodobnie zapewnią równoważne plany zapytań, ale nie ma rzeczywistej gwarancji.

Paul White 9
źródło
4

W przypadku łączenia wewnętrznego są one wymienne, ale w przypadku połączeń zewnętrznych mają różne znaczenia - ON jest zgodny, a GDZIE to proste filtrowanie. Lepiej więc trzymać się właściwego dopasowania składni JOIN w ON.

DaniSQL
źródło
4

OK, byłem ciekawy, więc zrobiłem test. Mam rzeczywiste plany wykonania dla następujących.

select * 
from sys.database_principals prin, sys.database_permissions perm
WHERE prin.principal_id = perm.grantee_principal_id

i

select * 
from sys.database_principals prin
JOIN sys.database_permissions perm
    ON prin.principal_id = perm.grantee_principal_id

Porównałem je obiekt po obiekcie i były identyczne. Przynajmniej dla bardzo prostego przykładu, wyszli na to samo. Sprawdziłem także statystyki IO i czas, a były one wystarczająco blisko, aby być tym samym.

To powiedziawszy, powinieneś użyć JOINskładni, ponieważ jest łatwiejsza do odczytania i rzadziej popełniasz błędy, szczególnie w skomplikowanych zapytaniach. A składnia *=/ =*dla OUTERzłączeń została już usunięta od SQL-Server 2005.

Kenneth Fisher
źródło