Veja a seguir uma simplificação de um problema de desempenho encontrado com o Query Store:
CREATE TABLE #tears
(
plan_id bigint NOT NULL
);
INSERT #tears (plan_id)
VALUES (1);
SELECT
T.plan_id
FROM #tears AS T
LEFT JOIN sys.query_store_plan AS QSP
ON QSP.plan_id = T.plan_id;
A plan_id
coluna está documentada como sendo a chave primária de sys.query_store_plan
, mas o plano de execução não usa a eliminação de junção como seria esperado:
- Nenhum atributo está sendo projetado do DMV.
- A chave primária DMV
plan_id
não pode duplicar linhas da tabela temporária - A
LEFT JOIN
é usado, portanto, nenhuma linha deT
pode ser eliminada.
Por que isso acontece e o que pode ser feito para obter a eliminação de junção aqui?
A documentação é um pouco enganosa. O DMV é uma visão não materializada e não possui uma chave primária como tal. As definições subjacentes são um pouco complexas, mas uma definição simplificada
sys.query_store_plan
é:Além disso,
sys.plan_persist_plan_merged
também é uma visualização, embora seja necessário conectar-se através da Conexão de Administrador Dedicado para ver sua definição. Novamente, simplificado:Os índices
sys.plan_persist_plan
são:Portanto
plan_id
, é restrito a ser único emsys.plan_persist_plan
.Agora,
sys.plan_persist_plan_in_memory
é uma função de streaming com valor de tabela, apresentando uma visão tabular de dados mantidos apenas em estruturas de memória interna. Como tal, ele não possui restrições exclusivas.No fundo, a consulta que está sendo executada é, portanto, equivalente a:
...que não produz eliminação de junção:
Indo direto ao cerne da questão, o problema é a consulta interna:
...claramente a junção esquerda pode resultar na
@t2
duplicação de linhas porque@t3
não tem restrição de exclusividade emplan_id
. Portanto, a junção não pode ser eliminada:Para contornar isso, podemos dizer explicitamente ao otimizador que não exigimos
plan_id
valores duplicados:A junção externa para
@t3
agora pode ser eliminada:Aplicando isso à consulta real:
Da mesma forma, poderíamos adicionar
GROUP BY T.plan_id
em vez doDISTINCT
. De qualquer forma, o otimizador agora pode raciocinar corretamente sobre oplan_id
atributo em todas as visualizações aninhadas e eliminar ambas as junções externas conforme desejado:Observe que tornar
plan_id
único na tabela temporária não seria suficiente para obter a eliminação de junção, pois não impediria resultados incorretos. Devemos rejeitar explicitamenteplan_id
valores duplicados do resultado final para permitir que o otimizador faça sua mágica aqui.