it-swarm.com.de

WHERE-Klausel vs. ON bei Verwendung von JOIN

Angenommen, ich habe den folgenden T-SQL-Code:

SELECT * FROM Foo f
INNER JOIN Bar b ON b.BarId = f.BarId;
WHERE b.IsApproved = 1;

Die folgende gibt auch die gleiche Menge von Zeilen zurück:

SELECT * FROM Foo f
INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId);

Dies ist möglicherweise nicht die beste Fallprobe, aber gibt es einen Leistungsunterschied zwischen diesen beiden?

41
tugberk

Nein, der Abfrageoptimierer ist intelligent genug, um den gleichen Ausführungsplan für beide Beispiele auszuwählen.

Sie können SHOWPLAN verwenden, um den Ausführungsplan zu überprüfen.


Sie sollten jedoch alle Join-Verbindungen in die ON-Klausel und alle Einschränkungen in der WHERE-Klausel aufnehmen.

29
aF.

Achten Sie einfach auf den Unterschied zu den äußeren Verbindungen. Eine Abfrage, bei der ein Filter von b.IsApproved (in der rechten Tabelle, Bar) zur ON-Bedingung der JOIN hinzugefügt wird:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

Ist NICHT dasselbe wie das Platzieren des Filters in der WHERE-Klausel:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved = 1); 

Da äußere Verknüpfungen für Bar "ausgefallen" sind (d. H., Wenn kein b.BarId für einen f.BarId vorhanden ist), wird b.IsApproved als NULL für alle derartigen fehlgeschlagenen Verbindungszeilen belassen, und diese Zeilen werden dann herausgefiltert. 

Eine andere Sichtweise besteht darin, dass LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) für die erste Abfrage immer die LEFT-Tabellenzeilen zurückgibt, da LEFT OUTER JOIN gewährleistet, dass die LEFT-Tabellenzeilen zurückgegeben werden, selbst wenn der Join fehlschlägt. Das Hinzufügen von (b.IsApproved = 1) zur LEFT OUTER JOIN-Bedingung bewirkt jedoch, NULL aus allen rechten Tabellenspalten herauszunehmen, wenn (b.IsApproved = 1) falsch ist, d. H. Nach den gleichen Regeln, die normalerweise auf eine LEFT JOIN-Bedingung in (b.BarId = f.BarId) angewendet werden.

Update : Um die Frage zu beantworten, die Conrad gestellt hat, lautet das entsprechende LOJ für einen OPTIONALEN Filter:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId)
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1);

die WHERE-Klausel muss sowohl die Bedingung berücksichtigen, ob der Join (NULL) fehlschlägt, und der Filter ignoriert wird, und wo der Join erfolgreich ist und der Filter angewendet werden muss. (b.IsApproved oder b.BarId könnte auf NULL getestet werden)

Ich habe hier ein SqlFiddle zusammengestellt , das die Unterschiede zwischen den verschiedenen Platzierungen des b.IsApproved-Filters relativ zur JOIN veranschaulicht.

43
StuartLC
SELECT * FROM Foo f
INNER JOIN Bar b ON b.BarId = f.BarId
WHERE b.IsApproved = 1;

Dies ist die bessere Form, um zu gehen. Es ist leicht zu lesen und leicht zu ändern. In der Geschäftswelt ist dies das, was Sie möchten. In Bezug auf die Leistung sind sie jedoch gleich.

6
Landin Martens

Ich habe gerade einen Abfrageversuch mit vier Tabellen durchgeführt - einer Primärtabelle mit drei INNER JOINs und insgesamt vier Parametern. Ich habe die Ausführungspläne beider Ansätze verglichen (anhand der Filterkriterien im ON des JOIN und dann auch im die WHERE-Klausel).

Die Ausführungspläne sind genau die gleichen. Ich habe dies auf SQL Server 2008 R2 ausgeführt.

0
Jason L

In einigen Fällen schien das Optimierungsprogramm selbst in den letzten Versionen von MSSQL nicht intelligent genug zu sein - und der Leistungsunterschied war ein Monster.

Dies ist jedoch eine Ausnahme. In den meisten Fällen wird der SQL Server-Optimierer das Problem lösen und den richtigen Plan erhalten.

Behalten Sie daher die Richtlinien der Verwendung von Filtern für die WHERE-Klausel bei und optimieren Sie sie bei Bedarf.

0
Fabricio Araujo