Usando visualizações indexadas para agregados - bom demais para ser verdade?

28

Temos um armazém de dados com uma contagem de registros bastante grande (10 a 20 milhões de linhas) e geralmente executamos consultas que contam registros entre determinadas datas ou contam registros com determinados sinalizadores, por exemplo,

SELECT
    f.IsFoo,
    COUNT(*) AS WidgetCount
FROM Widgets AS w
JOIN Flags AS f
    ON f.FlagId = w.FlagId
WHERE w.Date >= @startDate
GROUP BY f.IsFoo

O desempenho não é péssimo, mas pode ser relativamente lento (talvez 10 segundos em um cache frio).

Recentemente, descobri que posso usar GROUP BYem visualizações indexadas e, portanto, tentei algo semelhante ao seguinte

CREATE VIEW TestView
WITH SCHEMABINDING
AS
    SELECT
        Date,
        FlagId,
        COUNT_BIG(*) AS WidgetCount
    FROM Widgets
    GROUP BY Date, FlagId;
GO

CREATE UNIQUE CLUSTERED INDEX PK_TestView ON TestView
(
    Date,
    FlagId
);

Como resultado, o desempenho da minha primeira consulta agora é <100ms, e a exibição e o índice resultantes são <100k (embora nossa contagem de linhas seja grande, o intervalo de datas e os IDs de sinalizadores significa que essa exibição contém apenas de 1000 a 2000 linhas).

Eu pensei que talvez isso prejudicasse o desempenho das gravações na tabela Widget, mas não - o desempenho das inserções e atualizações nesta tabela não é afetado tanto quanto eu poderia dizer (além disso, por ser um data warehouse, essa tabela é atualizada com pouca frequência de qualquer forma)

Para mim, isso parece bom demais para ser verdade - não é? Com o que preciso ter cuidado ao usar modos de exibição indexados dessa maneira?

Justin
fonte
2
Você pode reescrever seus scripts para que eles sejam realmente válidos para SQL? Seu SELECTe CREATE VIEWscripts estão errados, como acredito que seja seu CREATE INDEXscript.
Mark Sinkinson
2
@MarkSinkinson Apologies, verifica-se que tentando escrever SQL válido para tabelas imaginários é difícil
Justin
A parte 'bom demais para ser verdade' para mim veio quando eu queria modos de exibição mais avançados, como aqueles que continham MAX, associações próprias ou externas ou indexação de um modo de exibição que faz referência a outro modo de exibição - todos no SQL Server pelo menos não são docs.microsoft.com/en-us/sql/relational-databases/views/… permitido . Por isso, sempre acabo sendo ambicioso demais e depois preciso reduzir as coisas. Mas para as agregações mais simples, elas são realmente ótimas - até o SUM é suportado.
Simon_Weaver

Respostas:

29

Como você observou, a própria exibição apenas materializa um pequeno número de linhas - portanto, mesmo se você atualizar a tabela inteira, a E / S adicional envolvida na atualização da exibição é desprezível. Você provavelmente já sentiu a maior dor que sentiu ao criar a exibição. O próximo mais próximo será se você adicionar um zilhão de linhas à tabela base com vários IDs novos que exigem novas linhas na exibição.

Isso não é bom demais para ser verdade. Você está usando exibições indexadas exatamente como elas deveriam ser usadas - ou pelo menos uma das maneiras mais eficazes: pagar por futuras agregações de consultas no momento da gravação. Isso funciona melhor quando o resultado é muito menor que a origem e, é claro, quando as agregações são solicitadas com mais frequência do que os dados subjacentes são atualizados (mais comum em DW que em OLTP, geralmente).

Infelizmente, muitas pessoas pensam que indexar uma visualização é mágica - um índice não tornará todas as visualizações mais eficientes, especialmente as que simplesmente juntam tabelas e / ou produzem o mesmo número de linhas que a fonte (ou até se multiplicam). Nesses casos, a E / S da exibição é a mesma ou até pior que a consulta original, não apenas porque há a mesma ou mais linhas, mas muitas vezes elas também estão armazenando e materializando mais colunas. Portanto, materializar antecipadamente não proporciona nenhum ganho, pois - mesmo com SSDs - E / S, rede e processamento / renderização de cliente ainda permanecem os principais gargalos no retorno de grandes conjuntos de resultados ao cliente. As economias que você obtém ao evitar a junção no tempo de execução simplesmente não são mensuráveis ​​em comparação com todos os outros recursos que você ainda está usando.

Como índices não agrupados, apenas tome cuidado para não exagerar. Se você adicionar 10 visualizações indexadas diferentes a uma tabela, terá mais impacto na parte de gravação da sua carga de trabalho, especialmente se as colunas de agrupamento não forem a chave de cluster.

Puxa, eu tenho intenção de blog sobre este tópico.

Aaron Bertrand
fonte
19

As respostas de Aarons cobriram bem essa pergunta. Duas coisas a acrescentar:

  1. As visualizações indexadas de agregação podem levar a disputas entre linhas e conflitos. Normalmente, duas inserções não entram em conflito (exceto para condições bastante raras, como escalada de bloqueio ou colisões de hash de bloqueio). Porém, se ambas as inserções abordarem o mesmo grupo na visualização, elas disputarão. O mesmo ponto representa qualquer outra coisa que use bloqueios (DML, dicas de bloqueio).
  2. Exibições indexadas que não agregam também podem ser úteis. Eles permitem indexar colunas de várias tabelas. Dessa forma, você pode filtrar com eficiência em uma tabela e ordenar por uma coluna a partir de uma tabela unida. Esse padrão pode converter a junção de tabela completa em pequenas consultas de tempo constante.

Eu usei agregação e ingresso em vistas com extremo benefício.

No geral, seu caso de uso parece ser um caso perfeito. As visualizações indexadas são uma técnica muito subutilizada.

usr
fonte