Performances de l'indice sur ON et WHERE

26

j'ai deux tables

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Ces tables ont un index non clusterisé le (Id, Date)

Et je rejoins ces tables

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

Cela peut également s'écrire

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

Ma question est, laquelle de ces deux requêtes donne les meilleures performances et pourquoi? Ou sont-ils égaux?

Erik Bergstedt
la source
1
Avez-vous vraiment une table @ variable avec un index non cluster qui couvre tous les champs, et aucun index cluster? ou est-ce juste une simplification?
Remus Rusanu
1
C'est une simplification extrême
Erik Bergstedt

Réponses:

32

La performance sera la même. L'optimiseur reconnaîtra cela et créera le même plan.

D'un autre côté, je ne dirais pas qu'ils sont égaux. La première forme de la question est beaucoup plus lisible et généralement attendue.

Pour un exemple utilisant certaines tables que j'ai sous la main, vous pouvez voir que le plan d'exécution est exactement le même, peu importe comment j'écris la requête.

Vous devriez être en mesure de déterminer les plans de requête pour vos propres tables et ensembles de données afin de pouvoir voir ce qui se passe dans votre situation.

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

Donne ces plans d'exécution

entrez la description de l'image ici

Tom V - Équipe Monica
la source
Je suis d'accord, le premier formulaire est plus facile à lire, et je suis donc soulagé qu'ils soient égaux. Je n'utiliserai ce formulaire qu'à l'avenir.
Erik Bergstedt
@ErikBergstedt J'ai modifié ma réponse, vous devriez pouvoir vérifier cela assez facilement pour votre propre ensemble de données et la structure de la table lorsque vous regardez les plans d'exécution
Tom V - Team Monica
Oui je l'ai fait. Merci. Je ne cherchais qu'un 2ème avis car je n'ai trouvé aucune réponse existante.
Erik Bergstedt
Remarque: Ils sont UNIQUEMENT égaux s'il s'agit d'un INNER JOIN. Si vous ajoutez un, OUTER JOINils ne sont décidément pas les mêmes.
Kenneth Fisher
22

Ils sont sémantiquement identiques et l'optimiseur ne devrait avoir aucun mal à reconnaître ce fait et à générer des plans identiques.

J'ai tendance à mettre des conditions faisant référence aux deux tables dans le ONet des conditions faisant référence à une seule table dans le WHERE.

Pour le OUTER JOINSdéplacement, les conditions peuvent cependant affecter la sémantique.

Martin Smith
la source
7

Dans les cas simples, ce sera la même chose. Cependant, j'ai vu des requêtes très complexes avec plusieurs jointures avoir des plans très différents. Une récente sur laquelle je travaillais a commencé avec une table qui a près de 6 millions de lignes jointes à environ 20 tables différentes. Seule la première jointure de cette table était une jointure interne , toutes les autres restaient des jointures externes. Le filtre dans la clause where a été paramétré quelque chose comme ceci:

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

Ce filtre a été utilisé plus tard dans le plan plutôt qu'avant. Lorsque j'ai déplacé ces conditions vers la première jointure interne, le plan a radicalement changé car le filtre a été appliqué au début du plan pour limiter le jeu de résultats et mon processeur et le temps écoulé ont chuté d'environ 310%. Ainsi, comme pour de nombreuses questions SQL Server, cela dépend.

Jared Karney
la source
2
Pourriez-vous ajouter plus de détails - peut-être des captures d'écran des diagrammes du plan d'exécution - car votre réponse semble contredire toutes les autres?
Kenny Evitt
2
Le plan a-t-il montré une temporisation d'optimisation?
Martin Smith
Comment la charge du processeur peut-elle chuter de plus de 100%?
Michael Green
2

En général, l'endroit où vous placez les filtres fait une différence.
Bien que Tom V indique que l'Optimizer reconnaîtra que les requêtes sont les mêmes et proposent le même plan, ce n'est pas toujours vrai. Cela dépend de la version de SQL que vous utilisez, de la complexité de votre requête et de l'importance du lot global que l'Optimizer détermine.

L'optimiseur peut décider que cette partie du lot ne vaut pas la peine de passer suffisamment de temps pour lui permettre d'élaborer le meilleur plan. En général, vous obtiendrez de meilleures performances si vous mettez des conditions qui réduisent la quantité de données sur lesquelles la requête devra travailler dans la clause ON au lieu de la clause WHERE (si possible, car le faire avec une jointure externe se traduira par un produit cartésien .)

Il est un peu plus facile pour le développeur SQL occasionnel de repérer les filtres dans la clause WHERE, mais j'ai travaillé sur de grandes tables où le fait d'avoir les filtres dans la clause ON réduit les heures de fonctionnement.

Donc, si la clause a le potentiel de réduire considérablement le nombre de lignes que la requête lira, je la mettrai toujours dans la clause ON pour aider l'Optimizer à choisir le meilleur plan.

Tom Evers
la source
1

Dans des circonstances ordinaires, les conditions de filtrage peuvent être spécifiées dans les clauses WHERE ou JOIN. J'ai tendance à placer des filtres sous WHERE à moins que la priorité OUTER JOIN ne soit affectée (voir ci-dessous) ou si le filtre est très spécifique à cette table (par exemple TYPE = 12 pour spécifier un sous-ensemble spécifique de lignes dans la table).

D'un autre côté, les clauses ON et WHERE peuvent être utilisées pour spécifier des conditions de jointure (par opposition aux conditions de filtrage). Tant que vous n'utilisez que des jointures INNER, peu importe ce que vous utilisez dans des circonstances ordinaires.

Cependant, si vous utilisez des jointures externes, cela peut faire une grande différence. Si, par exemple, vous spécifiez un OUTER JOIN entre deux tables (t1 et t2) mais que, dans la clause WHERE, continuez à spécifier une relation eqijoin entre les tables (par exemple t1.col = t2.col), vous avez juste converti la jointure OUTER en jointure INNER! En effet, WHERE peut être utilisé pour spécifier une équijoin (ou peut-être même une jointure OUTER, selon la version, en utilisant la syntaxe obsolète * =) sans utiliser de clause ON, et lorsque WHERE indique une équijoin interne entre les tables, elle remplace une OUTER REJOIGNEZ (le cas échéant).

La question initiale concernait les filtres, où le type de jointure ne devrait souvent pas être un problème, mais une jointure peut également agir comme un filtre et dans ces situations, le placement de la condition de jointure peut certainement avoir de l'importance.

McB2K3
la source
-1

Avec INNER JOINs, c'est un problème de style.

Cependant, cela devient beaucoup plus intéressant avec OUTER JOINs. Vous devez explorer les différences entre les requêtes avec OUTER JOIN et les conditions dans la clause ON et la clause WHERE. L'ensemble de résultats n'est pas toujours le même. Est, par exemple,

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

le même que

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL
Sean Redmond
la source
8
Si le résultat est différent (ce qui est bien sûr), quel est l'intérêt de comparer les performances?
ypercubeᵀᴹ