Ich habe zwei Tabellen mit identisch benannten, typisierten und indizierten Schlüsselspalten. Einer von ihnen hat einen eindeutigen Clustered-Index, der andere einen nicht eindeutigen .
Der Testaufbau
Setup-Skript, einschließlich einiger realistischer Statistiken:
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;
Der Repro
Wenn ich diese beiden Tabellen mit ihren Clustering-Schlüsseln verbinde, erwarte ich eine Eins-zu-viele-MERGE-Verknüpfung wie folgt:
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';
Dies ist der Abfrageplan, den ich möchte:
(Egal welche Warnungen, sie haben mit den gefälschten Statistiken zu tun.)
Wenn ich jedoch die Reihenfolge der Spalten in der Verknüpfung ändere, geschieht Folgendes:
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';
... das passiert:
Der Sortieroperator scheint die Streams in der angegebenen Reihenfolge des Joins zu ordnen, dh er c, a, b, d, e, f, g, h
fügt meinem Abfrageplan eine Blockierungsoperation hinzu.
Dinge, die ich angeschaut habe
- Ich habe versucht, die Spalten auf
NOT NULL
dieselben Ergebnisse zu ändern . - Die ursprüngliche Tabelle wurde mit erstellt
ANSI_PADDING OFF
, aber das Erstellen mitANSI_PADDING ON
hat keine Auswirkungen auf diesen Plan. - Ich habe
INNER JOIN
stattdessen versuchtLEFT JOIN
, keine Veränderung. - Ich entdeckte es auf einem 2014 SP2 Enterprise, erstellte einen Repro auf einem 2017 Developer (aktuelle CU).
- Das Entfernen der WHERE-Klausel in der führenden Indexspalte führt zwar zu einem guten Plan, wirkt sich jedoch auf die Ergebnisse aus. :)
Schließlich kommen wir zu der Frage
- Ist das beabsichtigt?
- Kann ich die Sortierung entfernen, ohne die Abfrage zu ändern (das ist der Herstellercode, also würde ich es lieber nicht tun ...)? Ich kann die Tabelle und die Indizes ändern.