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 BY
em 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?
SELECT
eCREATE VIEW
scripts estão errados, como acredito que seja seuCREATE INDEX
script.Respostas:
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.
fonte
As respostas de Aarons cobriram bem essa pergunta. Duas coisas a acrescentar:
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.
fonte