Eu tenho duas tabelas com colunas de chave identificadas, digitadas e indexadas. Um deles possui um índice clusterizado exclusivo , o outro possui um não exclusivo .
A configuração de teste
Script de instalação, incluindo algumas estatísticas realistas:
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;
A reprodução
Quando ingresso nessas duas tabelas em suas chaves de cluster, espero uma associação MERGE de um para muitos, assim:
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';
Este é o plano de consulta que eu quero:
(Não importa os avisos, eles têm a ver com estatísticas falsas.)
No entanto, se eu alterar a ordem das colunas na junção, assim:
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';
... isto acontece:
O operador Sort parece ordenar os fluxos de acordo com a ordem declarada da junção, ou seja c, a, b, d, e, f, g, h
, o que adiciona uma operação de bloqueio ao meu plano de consulta.
Coisas que eu olhei
- Eu tentei alterar as colunas para
NOT NULL
, mesmos resultados. - A tabela original foi criada com
ANSI_PADDING OFF
, mas criá-la comANSI_PADDING ON
não afeta esse plano. - Eu tentei um em
INNER JOIN
vez deLEFT JOIN
, nenhuma mudança. - Eu o descobri em um SP2 Enterprise de 2014, criei uma reprodução em um desenvolvedor de 2017 (CU atual).
- A remoção da cláusula WHERE na coluna principal do índice gera o bom plano, mas afeta os resultados .. :)
Finalmente, chegamos à questão
- Isso é intencional?
- Posso eliminar a classificação sem alterar a consulta (que é o código do fornecedor, então eu realmente prefiro não ...). Eu posso mudar a tabela e os índices.