Qual é o efeito da substituição de índices por índices filtrados (valor não nulo)?

10

Nosso projeto executa um banco de dados muito grande e muito complicado. Então, cerca de um mês atrás, percebemos que o espaço usado por colunas indexadas contendo valores nulos estava ficando muito grande. Como resposta a isso, escrevi como um script que pesquisaria dinamicamente todos os índices de coluna única contendo mais de 1% dos valores nulos, eliminando e recriando esses índices como índices filtrados, com a condição de que o valor NÃO fosse NULL. Isso descartaria e recriaria centenas de índices em todo o banco de dados e normalmente liberaria quase 15% do espaço usado por todo o banco de dados.

Agora eu tenho duas perguntas sobre isso:

A) Quais são as desvantagens do uso de índices filtrados dessa maneira? Eu diria que isso apenas melhoraria o desempenho, mas há algum risco de desempenho envolvido?

B) Recebemos erros ( 'não é possível descartar o índice XYZ porque ele não existe ou você não tem permissão' ) ao descartar e recriar os índices, mesmo que, depois de verificados, tudo tenha corrido exatamente como o esperado. Como isso pode acontecer?

Obrigado por qualquer ajuda!

Edit: Em resposta a @Thomas Kejser

Olá e obrigado, mas acontece que foi um desastre. Na época, não entendemos várias coisas, como:

  1. Durante uma consulta, o SQLOS faz planos de índice antes de determinar que não pode usar valores NULL para ingressar nas colunas da tabela. IE, você realmente precisa ter um filtro de cláusula WHERE que ajuste o índice para cada índice filtrado usado na consulta ou o índice não será usado.
  2. Descartar e criar índices e atualizar redundantemente suas estatísticas mais uma vez depois ainda pode não ser suficiente para produzir os planos atualizados, o que supusemos que eles faria. Em alguns casos, parece que apenas uma carga de trabalho alta o suficiente forçará o SQL Server a reavaliar os planos.
  3. Existem algumas características exóticas na funcionalidade do planejador de execução que são difíceis de determinar apenas pelo senso comum e pela lógica. Mesmo com milhares de variações geradas por código por trás de consultas diferentes, índices aparentemente inúteis podem ajudar em algumas estatísticas e planos de consulta que acabam sendo usados ​​em consultas críticas.

No final, essas mudanças foram revertidas. Portanto, os índices filtrados são uma ferramenta poderosa, mas você precisa realmente entender exatamente quais dados estão sendo buscados nessas colunas. Onde os índices normais, além dos problemas de espaço, são bastante fáceis de aplicar, os índices filtrados representam soluções muito personalizadas. Eles certamente não substituem um índice regular, mas uma extensão para eles nas circunstâncias especiais em que são necessários.

Kahn
fonte
Você também pode reexaminar sua estratégia de indexação. Se você possui centenas de índices de campo único, provavelmente não é o ideal.
JNK
A necessidade disso vem do fato de o banco de dados ser parcialmente herdado de outro sistema. Por padrão, temos algumas tabelas abstratas e várias colunas abstratas que não podem ser usadas, o que produz a maioria dessas quantidades massivas de valores NULL indexados. Quanto aos índices de campo único, eles são criados a partir do requisito básico de que cada chave estrangeira deve ser indexada e muitos deles estão nessas colunas que contêm principalmente ou apenas valores NULL.
Kahn

Respostas:

8

Abordagem muito interessante. Meu voto positivo pela criatividade.

Desde que você recuperou o espaço, presumo que os índices originais não estejam mais no lugar? As desvantagens dos índices filtrados são:

Em termos práticos, isso significa que você precisa ser extremamente cuidadoso com os índices filtrados, pois eles geralmente resultam em planos de consulta horríveis. Eu não chegaria a chamá-los de inúteis, mas os vejo como uma adição aos índices tradicionais, não como um substituto (como você está tentando fazer).

Thomas Kejser
fonte
"A parametrização de consulta não funciona com índices filtrados". isso pode provavelmente ser corrigido com opção (recompilação)
MichaelD
2

Thomas Kejser responde a este tópico bem acima.

Eu apenas pensei em adicionar 2 centavos.

Vi alguns índices filtrados sendo usados ​​apenas (mostrados no plano de execução) quando você corresponde exatamente à cláusula where na sua consulta como a where no índice filtrado.

você tentou usar visualizações indexadas ? colunas esparsas ?

Acredito que, desde que você tenha apenas juntas internas, é possível criar uma exibição indexada contendo a (s) cláusula (s) where de seus índices filtrados e, em seguida, você pode usá-la.

Pode haver mais de uma visualização. Mas, da mesma forma que nos índices não agrupados, muitos atrasarão sua anotação.

Na minha experiência, você teria bons ganhos em leitura, mas teria que monitorar gravações (inserções e atualizações), especialmente se as tabelas estiverem envolvidas na replicação.

No entanto, como eu entendo sua principal preocupação the null values, sugiro colunas SPARSE nos seus índices .

Colunas esparsas são especialmente apropriadas para índices filtrados

Como anunciei colunas esparsas, não me sentiria bem se também não dissesse suas limitações:

Ao projetar tabelas com colunas esparsas, lembre-se de que são necessários 2 bytes adicionais de sobrecarga para cada coluna esparsa não nula da tabela quando uma linha estiver sendo atualizada.

Como resultado disso

requisito de memória adicional, as atualizações podem falhar inesperadamente com o erro 576 quando o tamanho total da linha, incluindo essa sobrecarga de memória, exceder 8019,

e nenhuma coluna pode ser empurrada para fora da linha.

Considere o exemplo de uma tabela que possui 600 colunas esparsas do tipo bigint.

Se houver 571 colunas não nulas, o tamanho total no disco será 571 * 12 = 6852 bytes. Após incluir a sobrecarga de linha adicional e o cabeçalho da coluna esparsa, isso aumenta para cerca de 6895 bytes. A página ainda tem cerca de 1124 bytes disponíveis no disco. Isso pode dar a impressão de que colunas adicionais podem ser atualizadas com êxito. No entanto, durante a atualização, há uma sobrecarga adicional na memória que é 2 * (número de colunas esparsas não nulas). Neste exemplo, incluir a sobrecarga adicional - 2 * 571 = 1142 bytes - aumenta o tamanho da linha no disco para cerca de 8037 bytes. Esse tamanho excede o tamanho máximo permitido de 8019 bytes. Como todas as colunas são tipos de dados de comprimento fixo, elas não podem ser enviadas da linha. Como resultado, a atualização falha com o erro 576.

mais detalhes no link acima, porém prefiro postar aqui também este aviso:

Alterar uma coluna de esparso para não-esparso ou não-esparso para esparso requer a alteração do formato de armazenamento da coluna.

O Mecanismo de Banco de Dados do SQL Server usa o seguinte procedimento para realizar essa alteração:

1 - Adiciona uma nova coluna à tabela no novo tamanho e formato de armazenamento.

2 - Para cada linha da tabela, atualiza e copia o valor armazenado na coluna antiga para a nova coluna.

3 - Remove a coluna antiga do esquema da tabela.

4 - Reconstrói a tabela (se não houver índice em cluster) ou reconstrói o índice em cluster para recuperar o espaço usado pela coluna antiga.

Marcello Miorelli
fonte
11
Oi. Um pouco atrasado, mas sim, embora tenhamos abandonado a abordagem descrita neste tópico há muito tempo, voltamos recentemente a ela com uma abordagem mais seletiva. Basicamente, analisamos o uso de estatísticas e o modelo de negócios para confirmar os índices em uma tabela por tabela. Em seguida, testei adicionando um novo índice filtrado ao lado do normal e verifiquei, por algumas semanas, qual acabou sendo usado. Depois de confirmar que APENAS os índices filtrados foram usados ​​em novos planos, eliminamos os normais não filtrados.
Kahn
11
Além disso, alteramos algumas colunas para tipos esparsos. O problema disso, porém, é que, como você verá no MSDN, alterar um tipo de coluna para esparso basicamente força a recriação de todo o índice clusterizado. Tornando isso bastante pesado para tabelas grandes e complexas. Então, renomeamos as restrições e a tabela, criamos uma nova com o mesmo modelo e nome original, mas com colunas esparsas, e depois transferimos os dados para a nova tabela em lotes apropriados. Então, uma vez verificado se tudo estava ok e todos os índices e FKs estavam novamente no lugar, descartamos as tabelas antigas.
Kahn
11
Além disso, em alguns casos, o uso da compactação de páginas era muito preferível, então acabamos fazendo isso. Também é útil, pois você pode simplesmente criar o índice clusterizado existente com DROP_EXISTING = ON, para torná-lo muito, muito mais rápido do que seguir a rota esparsa. Especialmente porque evita todo o incômodo de re-gerenciar índices e FKs.
Kahn