Ho due tabelle con colonne chiave identificate, digitate e indicizzate. Uno di questi ha un indice cluster univoco , l'altro ha un indice non univoco .
L'impostazione del test
Script di installazione, incluse alcune statistiche realistiche:
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 riproduzione
Quando unisco queste due tabelle sulle loro chiavi di clustering, mi aspetto un join MERGE uno-a-molti, in questo modo:
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';
Questo è il piano di query che desidero:
(Non importa gli avvertimenti, hanno a che fare con le statistiche false.)
Tuttavia, se cambio l'ordine delle colonne attorno al join, in questo modo:
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';
... questo succede:
L'operatore di ordinamento sembra ordinare i flussi secondo l'ordine dichiarato del join, vale a dire c, a, b, d, e, f, g, h
che aggiunge un'operazione di blocco al mio piano di query.
Cose che ho visto
- Ho provato a cambiare le colonne in
NOT NULL
, stessi risultati. - La tabella originale è stata creata con
ANSI_PADDING OFF
, ma la sua creazioneANSI_PADDING ON
non influisce su questo piano. - Ho provato un
INNER JOIN
invece diLEFT JOIN
, nessun cambiamento. - L'ho scoperto su una SP2 Enterprise 2014, ho creato una riproduzione su uno sviluppatore del 2017 (attuale CU).
- La rimozione della clausola WHERE sulla colonna dell'indice principale genera un buon piano, ma influisce in qualche modo sui risultati .. :)
Finalmente arriviamo alla domanda
- È intenzionale?
- Posso eliminare l'ordinamento senza modificare la query (che è il codice del fornitore, quindi preferirei davvero ...). Posso cambiare la tabella e gli indici.