A documentação é um pouco enganadora. A 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 de sys.query_store_plan
é:
CREATE VIEW sys.query_store_plan AS
SELECT
PPM.plan_id
-- various other attributes
FROM sys.plan_persist_plan_merged AS PPM
LEFT JOIN sys.syspalvalues AS P
ON P.class = 'PFT'
AND P.[value] = plan_forcing_type;
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. Mais uma vez, simplificado:
CREATE VIEW sys.plan_persist_plan_merged AS
SELECT
P.plan_id as plan_id,
-- various other attributes
FROM sys.plan_persist_plan P
-- NOTE - in order to prevent potential deadlock
-- between QDS_STATEMENT_STABILITY LOCK and index locks
WITH (NOLOCK)
LEFT JOIN sys.plan_persist_plan_in_memory PM
ON P.plan_id = PM.plan_id;
Os índices em sys.plan_persist_plan
são:
╔════════════════════════╦════════════════════════ ══════════════╦═════════════╗
║ index_name ║ index_description ║ index_keys ║
╠════════════════════════╬════════════════════════ ══════════════╬═════════════╣
║ plan_persist_plan_cidx ║ clusterizado, exclusivo localizado em PRIMARY ║ plan_id ║
║ plan_persist_plan_idx1 ║ não clusterizado localizado no PRIMARY ║ query_id (-) ║
╚════════════════════════╩════════════════════════ ══════════════╩═════════════╝
Então, plan_id
é limitado 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 dos dados mantidos apenas nas estruturas de memória interna. Como tal, não possui restrições exclusivas.
No fundo, a consulta que está sendo executada é, portanto, equivalente a:
DECLARE @t1 table (plan_id integer NOT NULL);
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);
SELECT
T1.plan_id
FROM @t1 AS T1
LEFT JOIN
(
SELECT
T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3
ON T3.plan_id = T2.plan_id
) AS Q1
ON Q1.plan_id = T1.plan_id;
... que não produz eliminação de junção:
Chegando ao cerne da questão, o problema é a consulta interna:
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);
SELECT
T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3
ON T3.plan_id = T2.plan_id;
... claramente a junção esquerda pode resultar na @t2
duplicação de linhas porque @t3
não possui nenhuma restrição de exclusividade plan_id
. Portanto, a associação não pode ser eliminada:
Para contornar isso, podemos dizer explicitamente ao otimizador que não exigimos nenhum plan_id
valor duplicado :
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);
SELECT DISTINCT
T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3
ON T3.plan_id = T2.plan_id;
A junção externa para @t3
agora pode ser eliminada:
Aplicando isso à consulta real:
SELECT DISTINCT
T.plan_id
FROM #tears AS T
LEFT JOIN sys.query_store_plan AS QSP
ON QSP.plan_id = T.plan_id;
Da mesma forma, poderíamos adicionar em GROUP BY T.plan_id
vez de DISTINCT
. De qualquer forma, o otimizador agora pode raciocinar corretamente sobre o plan_id
atributo até as visualizações aninhadas e eliminar as junções externas conforme desejado:
Observe que tornar plan_id
exclusivo na tabela temporária não seria suficiente para obter a eliminação da junção, pois não impediria resultados incorretos. Devemos rejeitar explicitamente os plan_id
valores duplicados do resultado final para permitir que o otimizador trabalhe sua mágica aqui.