Vergleichen Sie diese beiden Abfragen. Ist es schneller, den Filter auf die Join-Kriterien oder in die WHERE
Klausel zu setzen ? Ich hatte immer das Gefühl, dass es bei den Join-Kriterien schneller ist, weil es die Ergebnismenge zum schnellstmöglichen Zeitpunkt reduziert, aber ich weiß es nicht genau.
Ich werde einige Tests erstellen, um zu sehen, aber ich wollte auch Meinungen dazu einholen, welche auch klarer zu lesen sind.
Abfrage 1
SELECT *
FROM TableA a
INNER JOIN TableXRef x
ON a.ID = x.TableAID
INNER JOIN TableB b
ON x.TableBID = b.ID
WHERE a.ID = 1 /* <-- Filter here? */
Abfrage 2
SELECT *
FROM TableA a
INNER JOIN TableXRef x
ON a.ID = x.TableAID
AND a.ID = 1 /* <-- Or filter here? */
INNER JOIN TableB b
ON x.TableBID = b.ID
BEARBEITEN
Ich habe einige Tests durchgeführt und die Ergebnisse zeigen, dass es tatsächlich sehr eng ist, aber die WHERE
Klausel ist tatsächlich etwas schneller! =)
Ich stimme absolut zu, dass es sinnvoller ist, den Filter auf die WHERE
Klausel anzuwenden. Ich war nur neugierig auf die Auswirkungen auf die Leistung.
ELAPSED TIME WHERE CRITERIA: 143016 ms
ELAPSED TIME JOIN CRITERIA: 143256 ms
PRÜFUNG
SET NOCOUNT ON;
DECLARE @num INT,
@iter INT
SELECT @num = 1000, -- Number of records in TableA and TableB, the cross table is populated with a CROSS JOIN from A to B
@iter = 1000 -- Number of select iterations to perform
DECLARE @a TABLE (
id INT
)
DECLARE @b TABLE (
id INT
)
DECLARE @x TABLE (
aid INT,
bid INT
)
DECLARE @num_curr INT
SELECT @num_curr = 1
WHILE (@num_curr <= @num)
BEGIN
INSERT @a (id) SELECT @num_curr
INSERT @b (id) SELECT @num_curr
SELECT @num_curr = @num_curr + 1
END
INSERT @x (aid, bid)
SELECT a.id,
b.id
FROM @a a
CROSS JOIN @b b
/*
TEST
*/
DECLARE @begin_where DATETIME,
@end_where DATETIME,
@count_where INT,
@begin_join DATETIME,
@end_join DATETIME,
@count_join INT,
@curr INT,
@aid INT
DECLARE @temp TABLE (
curr INT,
aid INT,
bid INT
)
DELETE FROM @temp
SELECT @curr = 0,
@aid = 50
SELECT @begin_where = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
INSERT @temp (curr, aid, bid)
SELECT @curr,
aid,
bid
FROM @a a
INNER JOIN @x x
ON a.id = x.aid
INNER JOIN @b b
ON x.bid = b.id
WHERE a.id = @aid
SELECT @curr = @curr + 1
END
SELECT @end_where = CURRENT_TIMESTAMP
SELECT @count_where = COUNT(1) FROM @temp
DELETE FROM @temp
SELECT @curr = 0
SELECT @begin_join = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
INSERT @temp (curr, aid, bid)
SELECT @curr,
aid,
bid
FROM @a a
INNER JOIN @x x
ON a.id = x.aid
AND a.id = @aid
INNER JOIN @b b
ON x.bid = b.id
SELECT @curr = @curr + 1
END
SELECT @end_join = CURRENT_TIMESTAMP
SELECT @count_join = COUNT(1) FROM @temp
DELETE FROM @temp
SELECT @count_where AS count_where,
@count_join AS count_join,
DATEDIFF(millisecond, @begin_where, @end_where) AS elapsed_where,
DATEDIFF(millisecond, @begin_join, @end_join) AS elapsed_join
quelle
Antworten:
In Bezug auf die Leistung sind sie gleich (und produzieren die gleichen Pläne)
Logischerweise sollten Sie die Operation ausführen, die immer noch sinnvoll ist, wenn Sie sie durch
INNER JOIN
eine ersetzenLEFT JOIN
.In Ihrem Fall sieht dies folgendermaßen aus:
oder dieses:
Die erstere Abfrage gibt keine tatsächlichen Übereinstimmungen für
a.id
andere als zurück1
, sodass die letztere Syntax (mitWHERE
) logisch konsistenter ist.quelle
a.id = 1
nur für die Kreuzung, nicht für den linken Teil ohne die Kreuzung.a.id != 1
das andere nur Zeilen enthält, in denena.id = 1
.Bei inneren Verknüpfungen spielt es keine Rolle, wo Sie Ihre Kriterien angeben. Der SQL-Compiler wandelt beide in einen Ausführungsplan um, in dem die Filterung unterhalb des Joins erfolgt (dh als ob die Filterausdrücke in der Join-Bedingung erscheinen).
Äußere Verknüpfungen sind eine andere Sache, da der Ort des Filters die Semantik der Abfrage ändert.
quelle
Soweit die beiden Methoden gehen.
Obwohl Sie sie anders verwenden können, scheint es mir immer ein Geruch zu sein.
Beschäftige dich mit Leistung, wenn es ein Problem ist. Dann können Sie sich solche "Optimierungen" ansehen.
quelle
Mit jedem Abfrageoptimierer haben sie einen Cent ... sie sind identisch.
quelle
In postgresql sind sie gleich. Wir wissen das, denn wenn Sie dies
explain analyze
bei jeder der Abfragen tun , ist der Plan derselbe. Nehmen Sie dieses Beispiel:Beide haben die gleichen minimalen und maximalen Kosten sowie den gleichen Abfrageplan. Beachten Sie außerdem, dass team_score_2 auch in der obersten Abfrage als 'Filter' angewendet wird.
quelle
Es ist wirklich unwahrscheinlich, dass die Platzierung dieses Joins der entscheidende Faktor für die Leistung ist. Ich bin mit der Ausführungsplanung für tsql nicht vertraut, aber es ist wahrscheinlich, dass sie automatisch für ähnliche Pläne optimiert werden.
quelle
Regel Nr. 0: Führen Sie einige Benchmarks durch und sehen Sie! Der einzige Weg, um wirklich zu sagen, was schneller sein wird, besteht darin, es zu versuchen. Diese Arten von Benchmarks sind mit dem SQL-Profiler sehr einfach durchzuführen.
Überprüfen Sie auch den Ausführungsplan für die Abfrage, die mit einer JOIN- und einer WHERE-Klausel geschrieben wurde, um festzustellen, welche Unterschiede auffallen.
Schließlich sollten diese beiden, wie andere bereits gesagt haben, von jedem anständigen Optimierer, einschließlich des in SQL Server integrierten Optimierers, identisch behandelt werden.
quelle
Ist es schneller Probieren Sie es aus und sehen Sie.
Welches ist leichter zu lesen? Das erste sieht für mich "korrekter" aus, da die verschobene Bedingung nichts wirklich mit dem Join zu tun hat.
quelle
Ich denke, das erste, weil es einen spezifischeren Filter über die Daten macht. Sie sollten den Ausführungsplan jedoch wie bei jeder Optimierung sehen, da er je nach Datengröße, Serverhardware usw. sehr unterschiedlich sein kann.
quelle