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.
quelle