Eu tenho uma coluna computada persistente em uma tabela que é simplesmente composta de colunas concatenadas, por exemplo
CREATE TABLE dbo.T
(
ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY,
A VARCHAR(20) NOT NULL,
B VARCHAR(20) NOT NULL,
C VARCHAR(20) NOT NULL,
D DATE NULL,
E VARCHAR(20) NULL,
Comp AS A + '-' + B + '-' + C PERSISTED NOT NULL
);
Como isso Comp
não é exclusivo, e D é a data de validade de cada combinação de A, B, C
, portanto, uso a seguinte consulta para obter a data de término de cada uma A, B, C
(basicamente a próxima data de início para o mesmo valor de Comp):
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1
WHERE t1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY t1.Comp;
Adicionei um índice à coluna computada para ajudar nessa consulta (e também em outras):
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
O plano de consulta, no entanto, me surpreendeu. Eu pensaria que, como tenho uma cláusula where afirmando isso D IS NOT NULL
e estou classificando por Comp
, e não fazendo referência a nenhuma coluna fora do índice, o índice na coluna computada poderia ser usado para varrer t1 e t2, mas vi um índice clusterizado digitalizar.
Então forcei o uso desse índice para ver se ele produzia um plano melhor:
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1 WITH (INDEX (IX_T_Comp_D))
WHERE t1.D IS NOT NULL
ORDER BY t1.Comp;
O que deu esse plano
Isso mostra que uma pesquisa de chave está sendo usada, cujos detalhes são:
Agora, de acordo com a documentação do SQL-Server:
Você pode criar um índice em uma coluna computada definida com uma expressão determinística, mas imprecisa, se a coluna estiver marcada como PERSISTED na instrução CREATE TABLE ou ALTER TABLE. Isso significa que o Mecanismo de Banco de Dados armazena os valores calculados na tabela e os atualiza quando quaisquer outras colunas das quais a coluna calculada depende são atualizadas. O Mecanismo de Banco de Dados usa esses valores persistentes quando cria um índice na coluna e quando o índice é referenciado em uma consulta. Essa opção permite criar um índice em uma coluna computada quando o Mecanismo de Banco de Dados não pode provar com precisão se uma função que retorna expressões de coluna calculada, particularmente uma função CLR criada no .NET Framework, é determinística e precisa.
Portanto, se, como os documentos dizem "o Mecanismo de Banco de Dados armazena os valores calculados na tabela" , e o valor também está sendo armazenado no meu índice, por que uma Pesquisa de Chave é necessária para obter A, B e C quando eles não são mencionados em a consulta? Suponho que eles estejam sendo usados para calcular Comp, mas por quê? Além disso, por que a consulta pode usar o índice em t2
, mas não em t1
?
Nota: eu marquei o SQL Server 2008 porque esta é a versão em que meu principal problema está, mas também recebo o mesmo comportamento em 2012.
FOJNtoLSJNandLASJN
) que resulta em coisas que não funcionam como seria de esperar e deixando lixo (BaseRow / Checksums) que é útil em alguns tipos de planos (por exemplo, cursores), mas não é necessário aqui.Chk
é soma de verificação! Obrigado, eu não tinha certeza disso. Originalmente, eu estava pensando que poderia ter algo a ver com restrições de verificação.Embora isso possa ser um pouco de coincidência devido à natureza artificial dos seus dados de teste, como você mencionou no SQL 2012, tentei reescrever:
Isso resultou em um bom plano de baixo custo usando seu índice e com leituras significativamente mais baixas que as outras opções (e os mesmos resultados para seus dados de teste).
Eu suspeito que seus dados reais são mais complicados, portanto, pode haver alguns cenários em que essa consulta se comporta semanticamente diferente da sua, mas às vezes mostra que os novos recursos podem fazer uma diferença real.
Eu experimentei alguns dados mais variados e encontrei alguns cenários para corresponder e outros não:
fonte
comp
não for uma coluna computada, você não verá a classificação.LEAD
função funcionou exatamente como eu gostaria na minha instância local do 2012 express. Infelizmente, esse pequeno inconveniente para mim ainda não foi considerado um motivo suficientemente bom para atualizar os servidores de produção ...Quando tentei executar as mesmas ações, obtive os outros resultados. Primeiro, meu plano de execução para tabela sem índices é o seguinte:
Como podemos ver na Análise de Índice em Cluster (t2), o predicado é usado para determinar as linhas necessárias a serem retornadas (devido à condição):
Quando o índice foi adicionado, independentemente de ter sido definido pelo operador WITH ou não, o plano de execução passou a ser o seguinte:
Como podemos ver, a verificação de índice em cluster é substituída pela verificação de índice. Como vimos acima, o SQL Server usa as colunas de origem da coluna computada para executar a correspondência da consulta aninhada. Durante a varredura de índice em cluster, todos esses valores podem ser adquiridos ao mesmo tempo (nenhuma operação adicional é necessária). Quando o índice foi adicionado, a filtragem das linhas necessárias da tabela (na seleção principal) está executando de acordo com o índice, mas os valores das colunas de origem da coluna computada
comp
ainda precisam ser obtidos (última operação Nested Loop) .Por esse motivo, a operação Key Lookup é usada - para obter os dados das colunas de origem da computada.
PS Parece um bug no SQL Server.
fonte