Em uma pergunta anterior minha, é uma boa ideia desabilitar a escalação de bloqueio ao adicionar novas colunas calculadas a uma tabela? , estou criando uma coluna computada:
ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
ISNULL(
CASE WHEN sintMarketID = 2
AND strType = 'CARD'
AND strTier1 LIKE 'GG%'
THEN 1
ELSE 0
END
, 0)
AS BIT
) PERSISTED;
A coluna calculada é PERSISTED
, e de acordo com computed_column_definition (Transact-SQL) :
PERSISTIDO
Especifica que o Mecanismo de Banco de Dados armazenará fisicamente os valores calculados na tabela e atualizará os valores quando quaisquer outras colunas das quais a coluna calculada depende forem atualizadas. Marcar uma coluna computada como PERSISTED permite que um índice seja criado em uma coluna computada que seja determinística, mas não precisa. Para obter mais informações, consulte índices em colunas computadas. Quaisquer colunas computadas usadas como colunas de particionamento de uma tabela particionada devem ser explicitamente marcadas como PERSISTED. computed_column_expression deve ser determinístico quando PERSISTED é especificado.
Mas quando tento criar um índice na minha coluna, recebo o seguinte erro:
CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo)
INCLUDE (strTier3)
WHERE isUsGift = 1;
O índice filtrado 'FIX_tblBGiftVoucherItem_incl' não pode ser criado na tabela 'dbo.tblBGiftVoucherItem' porque a coluna 'isUsGift' na expressão de filtro é uma coluna computada. Reescreva a expressão de filtro para que ela não inclua esta coluna.
Como posso criar um índice filtrado em uma coluna computada?
ou
Existe uma solução alternativa?
Infelizmente, a partir do SQL Server 2014, não há capacidade de criar um
Filtered Index
onde o filtro esteja em uma coluna computada (independentemente de ser ou não persistente).Há um Connect Item aberto desde 2009, então vá em frente e vote nele. Talvez a Microsoft conserte isso um dia.
Aaron Bertrand tem um artigo que aborda vários outros problemas com índices filtrados .
Embora você não possa criar um índice filtrado em uma coluna persistente, há uma solução bastante simples que você pode usar.
Como teste, criei uma tabela simples com uma
IDENTITY
coluna e uma coluna computada persistente com base na coluna de identidade:Em seguida, criei uma visualização vinculada ao esquema com base na tabela com um filtro na coluna computada:
Em seguida, criei um índice clusterizado na exibição vinculada ao esquema, que tem o efeito de persistir os valores armazenados na exibição, incluindo o valor da coluna computada:
Insira alguns dados de teste na tabela:
Crie um item de estatísticas e um índice na exibição:
A execução
SELECT
de instruções na tabela com a coluna persistente agora pode usar automaticamente a exibição persistente, se o otimizador de consulta determinar que faz sentido fazer isso:O plano de execução real para a consulta acima mostra que o otimizador de consulta escolheu usar a exibição persistente para retornar os resultados:
Você deve ter notado a conversão explícita na
WHERE
cláusula acima. Esse explícitoCONVERT(INT, 26)
permite que o otimizador de consulta use corretamente o objeto de estatísticas para estimar o número de linhas que serão retornadas pela consulta. Se escrevermos a consulta comWHERE pv.TestComputedColumn = 26
, o otimizador de consulta pode não estimar adequadamente o número de linhas, pois 26 é realmente considerado umTINY INT
; isso pode fazer com que o SQL Server não use a exibição persistente. As conversões implícitas podem ser muito dolorosas e vale a pena usar consistentemente os tipos de dados corretos para comparações e uniões.É claro que todas as "pegadinhas" padrão resultantes do uso de schema binding se aplicam ao cenário acima; isso pode impedir o uso dessa solução alternativa em todos os cenários. Por exemplo, não será mais possível modificar a tabela base sem primeiro remover a vinculação do esquema da exibição. Para fazer isso, você precisará remover o índice clusterizado da exibição.
Se você não tiver o SQL Server Enterprise Edition, o otimizador de consulta não usará automaticamente a exibição persistente para consultas que não fazem referência direta à exibição usando a
WITH (NOEXPAND)
dica. Para obter o benefício de usar a exibição persistente em versões não Enterprise Edition, você precisará reescrever a consulta acima para algo como:Obrigado a Ian Ringrose por apontar a limitação da Enterprise Edition acima e a Paul White pela
(NOEXPAND)
dica.Esta resposta de Paul tem alguns detalhes interessantes sobre o otimizador de consulta em relação a visualizações persistentes.
De
Create Index
e suawhere
cláusula, isso não é possível:Fonte: MSDN
Antes de calcularmos as colunas, usávamos gatilhos para calcular o valor das colunas sempre que a linha era alterada ou inserida.
(Um gatilho também pode ser usado para inserir/remover o PK do item de uma 2ª tabela que foi usada em consultas.)
Esta é uma tentativa de melhorar o trabalho de Hannah . Em sua solução, ela sugere o uso de 2 índices na exibição e um objeto de estatísticas.
O primeiro índice é clusterizado, o que é realmente necessário, pois, ao contrário de um índice não clusterizado em uma tabela, um erro será gerado se a criação de um índice não clusterizado na exibição for tentada sem primeiro ter um índice clusterizado.
O segundo índice é um índice não clusterizado, usado como o índice por trás da consulta. Na seção de comentários de sua resposta, perguntei o que aconteceria se um índice clusterizado fosse usado em vez de um índice não clusterizado.
A análise a seguir tenta responder a essa pergunta.
Estou usando exatamente o mesmo código, exceto que não estou criando um índice não clusterizado na exibição.
Também não estou criando um objeto de estatísticas. Se você estiver acompanhando e usando o SQL Server Management Studio (SSMS) para inserir o código abaixo, saiba que poderá ver algumas linhas onduladas vermelhas - que parecem erros. Estes (provavelmente) não são erros, mas envolvem um problema com o intellisense.
Você pode desabilitar o intellisense ou simplesmente ignorar os erros e executar os comandos. Eles devem ser concluídos sem erros.
O seguinte plano de execução (sem visualização/visualização de índice) é produzido depois que a seguinte consulta é executada na tabela:
Isso fornece uma linha de base para comparação. Observe que após a conclusão da consulta, um objeto de estatísticas foi criado (_WA_Sys_00000003_1FCDBCEB). O objeto de estatísticas PK_PersistedViewTest foi criado quando o índice de tabela em cluster foi criado.
Em seguida, a exibição filtrada e o índice clusterizado nessa exibição são criados:
Agora, vamos tentar executar a consulta novamente, mas desta vez contra a exibição:
O novo plano de execução é agora:
Se o novo plano for confiável, após a adição da exibição e do índice clusterizado nessa exibição, as estatísticas parecem indicar que o tempo necessário para executar a consulta dobrou. Além disso, observe que nenhum novo objeto de estatísticas foi criado para suportar o novo índice após a execução da consulta, o que é diferente da consulta na tabela.
O plano de consulta ainda sugere que a criação de um índice não clusterizado seria bastante útil para melhorar o desempenho da consulta. Então, isso significa que um índice não clusterizado deve ser adicionado à exibição antes que a melhoria de desempenho desejada possa ser obtida? Há uma última coisa a tentar. Modifique a consulta para usar a opção "WITH NOEXPAND":
Isso resulta no seguinte plano de consulta:
This execution plan looks quite similar to the one that was produced with the nonclustered index given in Hannah's answer. But, this one is done with one less (nonclustered) index and one less statistics object.
It turns out that the NOEXPAND option has to be used with the express and standard versions of SQL Server to make proper use of an indexed view. Paul White has an excellent article that expounds on the benefits of using the NOEXPAND option. He also recommends this option be used with the enterprise edition to ensure the uniqueness guarantee provided by the view indexes is used by the optimizer.
A análise acima foi feita com a edição expressa do SQL Server 2014. Também tentei com a edição do desenvolvedor do SQL Server 2016. A opção NOEXPAND não parece ser necessária com a edição de desenvolvimento para obter os ganhos de desempenho, mas ainda é recomendada .
Há menos de 5 meses, a Microsoft liberou as edições para desenvolvedores . A licença restringe o uso apenas para desenvolvimento, o que significa que o banco de dados não pode ser usado em um ambiente de produção. Portanto, se você está procurando testar tabelas com otimização de memória, criptografia, R etc., não tem mais a desculpa de não ter licença. Eu instalei com sucesso no meu computador há alguns dias junto com o SQL Server 2014 Express sem problemas.