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.