Mam dwie tabele z identycznie nazwanymi, wpisanymi i indeksowanymi kolumnami kluczy. Jeden z nich ma unikalny indeks klastrowy, drugi ma nieunikalny .
Konfiguracja testowa
Skrypt instalacyjny, w tym niektóre realistyczne statystyki:
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;
Repro
Kiedy dołączę do tych dwóch tabel na ich kluczach klastrowych, oczekuję połączenia jeden-do-wielu MERGE, tak:
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';
Oto plan zapytań, który chcę:
(Nieważne ostrzeżenia, mają one związek z fałszywymi statystykami.)
Jeśli jednak zmienię kolejność kolumn w złączeniu, to tak:
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';
... to się stało:
Wydaje się, że operator sortowania porządkuje strumienie zgodnie z zadeklarowaną kolejnością łączenia, tzn. c, a, b, d, e, f, g, h
Dodaje operację blokującą do mojego planu zapytań.
Rzeczy, na które patrzyłem
- Próbowałem zmienić kolumny na
NOT NULL
, te same wyniki. - Oryginalna tabela została utworzona za pomocą
ANSI_PADDING OFF
, ale jej utworzenieANSI_PADDING ON
nie wpływa na ten plan. - Próbowałem
INNER JOIN
zamiastLEFT JOIN
, bez zmian. - Odkryłem to na 2014 SP2 Enterprise, stworzyłem repro na 2017 Developer (obecna CU).
- Usunięcie klauzuli WHERE w wiodącej kolumnie indeksu generuje dobry plan, ale w pewnym stopniu wpływa na wyniki .. :)
Wreszcie dochodzimy do pytania
- Czy to celowe?
- Czy mogę wyeliminować sortowanie bez zmiany zapytania (który jest kodem dostawcy, więc wolałbym nie ...). Mogę zmienić tabelę i indeksy.
źródło