Comparez ces 2 requêtes. Est-il plus rapide de mettre le filtre sur les critères de jointure ou dans la WHERE
clause. J'ai toujours pensé que c'était plus rapide sur les critères de jointure car cela réduisait le jeu de résultats le plus tôt possible, mais je ne sais pas avec certitude.
Je vais construire quelques tests pour voir, mais je voulais aussi avoir des opinions sur ce qui serait plus clair à lire aussi.
Requête 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? */
Requête 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
ÉDITER
J'ai fait quelques tests et les résultats montrent que c'est en fait très proche, mais la WHERE
clause est en fait légèrement plus rapide! =)
Je suis tout à fait d'accord qu'il est plus logique d'appliquer le filtre sur l' WHERE
article, j'étais simplement curieux de connaître les implications sur le rendement.
TEMPS ÉCOULÉ O CRITÈRES: 143016 ms
TEMPS ÉCOULÉ CRITÈRES DE JOINT : 143256 ms
TESTER
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
la source
Réponses:
En termes de performances, ils sont identiques (et produisent les mêmes plans)
Logiquement, vous devez effectuer l'opération qui a encore du sens si vous remplacez
INNER JOIN
par unLEFT JOIN
.Dans votre cas, cela ressemblera à ceci:
ou ca:
La première requête ne renverra aucune correspondance réelle pour
a.id
autre que1
, donc la dernière syntaxe (avecWHERE
) est logiquement plus cohérente.la source
a.id = 1
s'applique uniquement à l'intersection, et non à la partie gauche excluant l'intersection.a.id != 1
, l'autre n'aura que des lignes oùa.id = 1
.Pour les jointures internes, peu importe où vous mettez vos critères. Le compilateur SQL transformera les deux en un plan d'exécution dans lequel le filtrage se produit sous la jointure (c'est-à-dire comme si les expressions de filtre apparaissaient dans la condition de jointure).
Les jointures externes sont une autre affaire, car l'emplacement du filtre modifie la sémantique de la requête.
la source
En ce qui concerne les deux méthodes.
Bien que vous puissiez les utiliser différemment, cela me semble toujours une odeur.
Gérez les performances quand c'est un problème. Ensuite, vous pouvez examiner ces «optimisations».
la source
Avec n'importe quel optimiseur de requêtes à un centime .... ils sont identiques.
la source
Dans postgresql, ce sont les mêmes. Nous le savons car si vous faites
explain analyze
sur chacune des requêtes, le plan s'avère être le même. Prenons cet exemple:Ils ont tous les deux le même coût minimum et maximum ainsi que le même plan de requête. Notez également que même dans la requête du haut, team_score_2 est appliqué en tant que «filtre».
la source
Il est très peu probable que le placement de cette jointure soit le facteur décisif pour les performances. Je ne suis pas intimement familier avec la planification d'exécution de tsql, mais il est probable qu'ils seront optimisés automatiquement sur des plans similaires.
la source
Règle n ° 0: exécutez quelques benchmarks et voyez! La seule façon de vraiment savoir ce qui sera le plus rapide est de l'essayer. Ces types de benchmarks sont très faciles à réaliser à l'aide du profileur SQL.
Examinez également le plan d'exécution de la requête écrite avec un JOIN et une clause WHERE pour voir quelles différences ressortent.
Enfin, comme d'autres l'ont dit, ces deux devraient être traités de la même manière par tout optimiseur décent, y compris celui intégré à SQL Server.
la source
Est-ce plus rapide? Essayez-le et voyez.
Qu'est-ce qui est plus facile à lire? Le premier me semble plus "correct", car la condition déplacée n'a rien à voir avec la jointure.
la source
Je suppose que le premier, car il fait un filtre plus spécifique sur les données. Mais vous devriez voir le plan d'exécution , comme pour toute optimisation, car il peut être très différent en fonction de la taille des données, du matériel du serveur, etc.
la source