Ist ein Join zur Laufzeit auf eine where-Klausel optimiert?

14

Wenn ich so eine Frage schreibe ...

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

Ist sich der SQL-Optimierer nicht sicher, ob das der richtige Begriff ist? Übersetzen Sie dies in ...

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

Ist die Join-Anweisung in SQL Server eine einfachere Möglichkeit, SQL zu schreiben? Oder wird es tatsächlich zur Laufzeit verwendet?

Bearbeiten: Ich verwende fast immer und fast immer die Join-Syntax. Ich bin nur gespannt was passiert.

Mr. Ant
quelle
1
Könnten Sie das "Fast" näher erläutern? Wann würden Sie die alte Syntax verwenden und warum?
Aaron Bertrand
2
Ein Randfall, bei dem es einen Unterschied macht, ist, wenn Sie ein (veraltetes) GROUP BY ALLin hinzufügen
Martin Smith
@MartinSmith benutzt jemand GROUP BY ALLabsichtlich? :-)
Aaron Bertrand
@ AaronBertrand - Ich bezweifle es! Glaube nicht, dass ich jemals jemanden gesehen habe, der es benutzt.
Martin Smith

Antworten:

20

Diese brechen innerlich auf dasselbe zusammen. Ersteres sollten Sie immer schreiben . Was noch wichtiger ist, warum ist das wichtig? Sie sind in Bezug auf Ausführungsplan und Leistung identisch (vorausgesetzt, Sie bringen es nicht durcheinander, was mit der faulen Syntax des alten Stils einfacher ist).

Hier ist der Beweis mit AdventureWorks, dass es keine gibt CROSS JOINund filterweitergeht.


Die explizite Verknüpfung:

Bildbeschreibung hier eingeben


Die implizite Verknüpfung:

Bildbeschreibung hier eingeben


Schau, ma! Identische Pläne, identische Ergebnisse, keine Cross-Joins oder Filter, die irgendwo zu sehen sind.

(Aus Gründen der Übersichtlichkeit handelt es sich bei der Warnung für den SELECTOperator in beiden Fällen um eine die Kardinalität beeinflussende implizite Konvertierung, die in beiden Fällen nichts mit dem Join zu tun hat.)

Aaron Bertrand
quelle
20

Genau genommen gibt es einen Unterschied in der Eingabe in das Abfrageoptimierungsprogramm zwischen den beiden Formularen:

-- 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);

ISO-89-Eingabebaum

-- 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);

ISO-92-Eingabebaum

Wie Sie sehen, ONist das Klauselprädikat mithilfe der modernen Syntax eng an den Join gebunden. Bei der älteren Syntax gibt es einen logischen Cross-Join, gefolgt von einer relationalen Auswahl (einem Zeilenfilter).

Das Abfrageoptimierungsprogramm reduziert während der Optimierung fast immer die relationale Auswahl in den Join. Dies bedeutet, dass die beiden Formulare höchstwahrscheinlich äquivalente Abfragepläne erstellen, es gibt jedoch keine tatsächliche Garantie.

Paul White Monica wieder einsetzen
quelle
4

Für innere Verknüpfungen sind sie austauschbar, aber für äußere Verknüpfungen haben sie unterschiedliche Bedeutungen - das EIN stimmt überein und WO ist einfaches Filtern. Deshalb ist es besser, die korrekte JOIN-Syntaxübereinstimmung auf ON beizubehalten.

DaniSQL
quelle
4

OK, ich war neugierig und habe einen Test gemacht. Ich habe aktuelle Ausführungspläne für Folgendes.

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

und

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

Ich habe sie Objekt für Objekt verglichen und sie waren identisch. Zumindest für ein sehr einfaches Beispiel kamen sie zu dem gleichen Ergebnis. Ich habe auch die Statistiken IO und Time überprüft und sie waren nah genug, um dasselbe zu sein.

Trotzdem sollten Sie die JOINSyntax verwenden, da sie einfacher zu lesen ist und Sie weniger wahrscheinlich Fehler machen, insbesondere bei komplizierten Abfragen. Und die *=/ =*Syntax für OUTERJoins wurde bereits ab SQL-Server 2005 entfernt.

Kenneth Fisher
quelle