Indexperformance auf ON versus WHERE


26

Ich habe zwei Tische

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Diese Tabellen haben einen nicht gruppierten Index für (ID, Datum).

Und ich verbinde diese Tische

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Dies kann auch als geschrieben werden

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Meine Frage ist, welche dieser beiden Abfragen die bessere Leistung liefert und warum? Oder sind sie gleich?


1
Haben Sie wirklich eine @table-Variable mit einem nicht gruppierten Index, der alle Felder abdeckt, und keinem gruppierten Index? oder ist nur eine Vereinfachung?
Remus Rusanu

1
Es ist eine extreme Vereinfachung
Erik Bergstedt

Antworten:


32

Die Leistung wird gleich sein. Der Optimierer erkennt dies und erstellt denselben Plan.

Andererseits würde ich nicht sagen, dass sie gleich sind. Das erste Formular in der Frage ist weitaus besser lesbar und wird allgemein erwartet.

Für ein Beispiel mit einigen Tabellen, die ich zur Hand habe, können Sie sehen, dass der Ausführungsplan genau der gleiche ist, egal wie ich die Abfrage schreibe.

Sie sollten in der Lage sein, die Abfragepläne für Ihre eigenen Tabellen und Datensätze zu bestimmen, damit Sie sehen können, was in Ihrer Situation passiert.

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Gibt diese Ausführungspläne

Bildbeschreibung hier eingeben


Ich stimme zu, das erste Formular ist leichter zu lesen und ich bin daher erleichtert, dass sie gleich sind. Ich werde dieses Formular in Zukunft nur noch verwenden.
Erik Bergstedt

@ErikBergstedt Ich habe meine Antwort bearbeitet. Wenn Sie sich die Ausführungspläne ansehen
Tom V - Team Monica,

Ja, habe ich. Vielen Dank. Ich habe nur nach einer zweiten Meinung gesucht, da ich keine Antwort gefunden habe.
Erik Bergstedt

Hinweis: Sie sind NUR gleich, wenn es sich um eine handelt INNER JOIN. Wenn Sie ein werfen, OUTER JOINdann sind sie entschieden nicht das selbe.
Kenneth Fisher

22

Sie sind semantisch identisch, und der Optimierer sollte keine Probleme haben, diese Tatsache zu erkennen und identische Pläne zu generieren.

Ich neige dazu, Bedingungen, die auf beide Tabellen ONverweisen, und Bedingungen, die nur auf eine Tabelle in der Tabelle verweisen, in die Tabelle aufzunehmen WHERE.

Zum OUTER JOINSVerschieben können die Bedingungen jedoch die Semantik beeinflussen.


7

In einfachen Fällen ist es dasselbe. Ich habe jedoch gesehen, dass sehr komplexe Abfragen mit mehreren Joins signifikant unterschiedliche Pläne haben. Bei einer kürzlich von mir bearbeiteten Tabelle wurden fast 6 Millionen Zeilen mit etwa 20 verschiedenen Tabellen verknüpft. Nur die erste Verknüpfung zu dieser Tabelle war eine innere Verknüpfung, alle anderen wurden äußere Verknüpfungen gelassen. Der Filter in der where-Klausel wurde folgendermaßen parametrisiert:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Dieser Filter wurde später im Plan anstelle von früher verwendet. Als ich diese Bedingungen in die erste innere Verknüpfung verschoben habe, hat sich der Plan dramatisch geändert, da der Filter zu Beginn des Plans angewendet wurde, um die Ergebnismenge zu begrenzen, und meine CPU und die verstrichene Zeit um ca. 310% gesunken sind. Wie bei vielen SQL Server-Fragen kommt es also darauf an.


2
Könnten Sie weitere Details hinzufügen - möglicherweise Screenshots der Ausführungsplandiagramme -, da Ihre Antwort allen anderen zu widersprechen scheint?
Kenny Evitt

2
Wurde im Plan eine Zeitüberschreitung für das Optimierungsprogramm festgestellt?
Martin Smith

Wie kann die CPU-Auslastung möglicherweise um mehr als 100% sinken?
Michael Green

2

Im Allgemeinen macht es einen Unterschied, wo Sie die Filter einsetzen.
Während Tom V angibt, dass der Optimierer erkennt, dass die Abfragen identisch sind, und denselben Plan erstellt, ist dies nicht immer der Fall. Dies hängt davon ab, in welcher SQL-Version Sie sich befinden, wie komplex Ihre Abfrage ist und wie wichtig die Abfrage für den gesamten Stapel ist, den das Optimierungsprogramm ermittelt.

Der Optimierer entscheidet möglicherweise, dass dieser Teil des Stapels nicht genügend Zeit kostet, um den besten Plan zu erstellen. Im Allgemeinen erhalten Sie eine bessere Leistung, wenn Sie in der ON-Klausel anstelle der WHERE-Klausel Bedingungen angeben, die die Datenmenge verringern, an der die Abfrage arbeiten muss (sofern möglich, da dies mit einem Outer Join zu einem kartesischen Produkt führt) .)

Es ist für den gelegentlichen SQL-Entwickler etwas einfacher, Filter in der WHERE-Klausel zu erkennen, aber ich habe an einigen großen Tabellen gearbeitet, in denen die Filter in der ON-Klausel die Laufzeit um Stunden verkürzen.

Wenn die Klausel die Anzahl der von der Abfrage gelesenen Zeilen drastisch reduzieren kann, werde ich sie immer in die ON-Klausel einfügen, damit der Optimierer den besseren Plan auswählen kann.


1

Unter normalen Umständen können Filterbedingungen entweder in WHERE- oder in JOIN-Klauseln angegeben werden. Ich neige dazu, Filter unter WHERE zu platzieren, es sei denn, die Priorität von OUTER JOIN könnte beeinträchtigt werden (siehe unten) oder der Filter ist sehr spezifisch für diese Tabelle (z. B. TYPE = 12, um eine bestimmte Teilmenge von Zeilen in der Tabelle anzugeben).

Andererseits können sowohl ON- als auch WHERE-Klauseln verwendet werden, um Verknüpfungsbedingungen (im Gegensatz zu Filterbedingungen) anzugeben. Solange Sie nur INNER-Joins verwenden, spielt es keine Rolle, welche Sie unter normalen Umständen verwenden.

Wenn Sie jedoch OUTER-Joins verwenden, kann dies einen großen Unterschied machen. Wenn Sie beispielsweise einen OUTER JOIN zwischen zwei Tabellen (t1 und t2) angeben, dann aber in der WHERE-Klausel eine eqijoin-Beziehung zwischen den Tabellen angeben (z. B. t1.col = t2.col), haben Sie gerade OUTER-Join in INNER-Join konvertiert! Dies liegt daran, dass mit WHERE ein Equijoin (oder möglicherweise sogar ein OUTER-Join, je nach Version mit der veralteten * = -Syntax) ohne Verwendung einer ON-Klausel angegeben werden kann. Wenn WHERE ein inneres Equijoin zwischen Tabellen angibt, überschreibt es ein OUTER JOIN (falls vorhanden).

Die ursprüngliche Frage betraf Filter, bei denen die Art des Joins häufig kein Problem sein sollte, ein Join jedoch auch als Filter fungieren kann. In diesen Situationen kann die Platzierung der Join-Bedingung mit Sicherheit eine Rolle spielen.


-1

Bei INNER JOINs ist dies ein Stilproblem.

Mit OUTER JOINs wird es jedoch viel interessanter. Sie sollten die Unterschiede zwischen Abfragen mit OUTER JOINs und Bedingungen sowohl in der ON-Klausel als auch in der WHERE-Klausel untersuchen. Die Ergebnismenge ist nicht immer dieselbe. Ist zum Beispiel

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

das Gleiche wie

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL

8
Wenn das Ergebnis anders ist (was es natürlich ist), wozu dient der Leistungsvergleich?
ypercubeᵀᴹ
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.