J'ai deux tables avec des colonnes clés identiques, typées et indexées. L'un d'eux a un index cluster unique , l'autre un non-unique .
La configuration du test
Script d'installation, incluant des statistiques réalistes:
DROP TABLE IF EXISTS #left;
DROP TABLE IF EXISTS #right;
CREATE TABLE #left (
a char(4) NOT NULL,
b char(2) NOT NULL,
c varchar(13) NOT NULL,
d bit NOT NULL,
e char(4) NOT NULL,
f char(25) NULL,
g char(25) NOT NULL,
h char(25) NULL
--- and a few other columns
);
CREATE UNIQUE CLUSTERED INDEX IX ON #left (a, b, c, d, e, f, g, h)
UPDATE STATISTICS #left WITH ROWCOUNT=63800000, PAGECOUNT=186000;
CREATE TABLE #right (
a char(4) NOT NULL,
b char(2) NOT NULL,
c varchar(13) NOT NULL,
d bit NOT NULL,
e char(4) NOT NULL,
f char(25) NULL,
g char(25) NOT NULL,
h char(25) NULL
--- and a few other columns
);
CREATE CLUSTERED INDEX IX ON #right (a, b, c, d, e, f, g, h)
UPDATE STATISTICS #right WITH ROWCOUNT=55700000, PAGECOUNT=128000;
La repro
Lorsque je joins ces deux tables sur leurs clés de cluster, j'attends une fusion MERGE un à plusieurs, comme ceci:
SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
l.a=r.a AND
l.b=r.b AND
l.c=r.c AND
l.d=r.d AND
l.e=r.e AND
l.f=r.f AND
l.g=r.g AND
l.h=r.h
WHERE l.a='2018';
C'est le plan de requête que je veux:
(Peu importe les avertissements, ils ont à voir avec les fausses statistiques.)
Cependant, si je change l'ordre des colonnes autour de la jointure, comme ceci:
SELECT *
FROM #left AS l
LEFT JOIN #right AS r ON
l.c=r.c AND -- used to be third
l.a=r.a AND -- used to be first
l.b=r.b AND -- used to be second
l.d=r.d AND
l.e=r.e AND
l.f=r.f AND
l.g=r.g AND
l.h=r.h
WHERE l.a='2018';
... ça arrive:
L'opérateur de tri semble ordonner les flux en fonction de l'ordre déclaré de la jointure, c'est c, a, b, d, e, f, g, h
-à- dire , ce qui ajoute une opération de blocage à mon plan de requête.
Choses que j'ai regardées
- J'ai essayé de changer les colonnes pour obtenir les
NOT NULL
mêmes résultats. - La table d'origine a été créée avec
ANSI_PADDING OFF
, mais sa créationANSI_PADDING ON
n'affecte pas ce plan. - J'ai essayé un
INNER JOIN
au lieu deLEFT JOIN
, pas de changement. - Je l'ai découvert sur un SP2 Enterprise 2014, j'ai créé une repro sur un développeur 2017 (CU actuelle).
- La suppression de la clause WHERE sur la colonne d’indexation principale génère le bon plan, mais cela affecte en quelque sorte les résultats .. :)
Enfin, nous arrivons à la question
- Est-ce intentionnel?
- Puis-je éliminer le tri sans changer la requête (qui est le code du fournisseur, donc je préfère ne pas le faire ...). Je peux changer la table et les index.
la source