Periodicamente, novos valores são adicionados graphou um valor existente é atualizado. Desejo atualizar a exibição a graph_avgcada duas horas apenas para os valores que foram atualizados. No entanto, no PostgreSQL 9.3, a tabela inteira é atualizada. Isso consome bastante tempo. A próxima versão 9.4 permite CONCURRENTatualização, mas ainda atualiza a exibição inteira. Com centenas de milhões de linhas, isso leva alguns minutos.
Qual é uma boa maneira de acompanhar os valores atualizados e novos e atualizar a exibição apenas parcialmente?
Você sempre pode implementar sua própria tabela, servindo como "visualização materializada". Isso é o que você tinha que fazer antes de MATERIALIZED VIEWser implementado no Postgres 9.3 de qualquer maneira.
Por exemplo, você pode criar uma planície VIEW:
CREATEVIEW graph_avg_view ASSELECT xaxis, AVG(value)AS avg_val
FROM graph
GROUPBY xaxis;
E materialize o resultado como um todo uma vez ou sempre que precisar começar de novo:
(Ou use a SELECTinstrução diretamente, sem criar a VIEW.)
Então, dependendo dos detalhes não revelados do seu caso de uso, você pode DELETE/ UPDATE/ INSERTalterar manualmente.
Uma instrução DML básica com CTEs modificadores de dados para sua tabela, como é :
Assumindo Ninguém tenta outra pessoa para escrever a graph_avgconcorrentemente (leitura não é problema):
WITH del AS(DELETEFROM graph_avg t
WHERENOTEXISTS(SELECT1FROM graph_avg_view v WHERE v.xaxis = v.xaxis);), upd AS(UPDATE graph_avg t
FROM graph_avg_view v
WHERE t.xaxis = v.xaxis
AND t.avg_val <> v.avg_val
)INSERTINTO graph_avg t
SELECT*FROM graph_avg_view v
LEFTJOIN graph_avg t USING(xaxis)WHERE t.xaxis ISNULL;
Mas isso provavelmente deve ser otimizado.
Receita básica:
Adicione uma timestampcoluna com padrão now()à sua tabela base. Vamos chamá-lo ts.
Se você tiver atualizações, adicione um gatilho para definir o carimbo de data / hora atual a cada atualização que seja alterada xaxisou value.
Crie uma pequena tabela para lembrar o carimbo de data e hora do seu instantâneo mais recente. Vamos chamá-lo mv:
CREATETABLE mv (
tbl text PRIMARYKEY, ts timestamp NOTNULLDEFAULT'-infinity');-- possibly more details
Crie este índice parcial, com várias colunas:
CREATEINDEX graph_mv_latest ON graph (xaxis, value)WHERE ts >='-infinity';
Use o registro de data e hora do último instantâneo como predicado em suas consultas para atualizar o instantâneo com o uso perfeito do índice.
No final da transação, descarte o índice e recrie-o com o registro de data e hora da transação, substituindo o registro de data e hora no predicado do índice (inicialmente '-infinity'), que você também salva na sua tabela. Tudo em uma transação.
Observe que o índice parcial é ótimo para cobrir INSERTe UPDATEoperações, mas não DELETE. Para cobrir isso, você precisa considerar a tabela inteira. Tudo depende dos requisitos exatos.
Obrigado pela clareza das visualizações materializadas e por sugerir uma resposta alternativa.
user4150760
13
Atualização simultânea (Postgres 9.4)
Embora não seja uma atualização incremental conforme solicitado, o Postgres 9.4 fornece um novo recurso de atualização simultânea .
Para citar o documento…
Antes do PostgreSQL 9.4, atualizar uma exibição materializada significava bloquear toda a tabela e, portanto, impedir que qualquer consulta fosse realizada; se uma atualização levasse muito tempo para adquirir o bloqueio exclusivo (enquanto aguarda as consultas para finalizá-lo), por sua vez está mantendo consultas subsequentes. Agora isso pode ser mitigado com a palavra-chave CONCURRENTLY:
Um índice exclusivo precisará existir na exibição materializada. Em vez de bloquear a visualização materializada, ela cria uma versão atualizada temporária, compara as duas versões e aplica INSERTs e DELETEs na visualização materializada para aplicar a diferença. Isso significa que as consultas ainda podem usar a visualização materializada enquanto estão sendo atualizadas. Diferentemente de sua forma não simultânea, as tuplas não são congeladas e precisam de VACUUM devido aos DELETEs mencionados acima que deixarão as tuplas mortas para trás.
Esta atualização simultânea ainda está executando uma nova consulta completa (não incremental). Portanto, CONCURRENTLY não economiza no tempo total de computação, apenas minimiza o tempo que sua visualização materializada fica indisponível para uso durante sua atualização.
Por um momento, fiquei empolgado até ler atentamente. it instead creates a temporary updated version of it...compares the two versions- Isso significa que a versão atualizada temporária ainda é uma computação completa e aplica a diferença à visualização existente. Então, essencialmente, ainda estou refazendo TODOS os cálculos, mas apenas na tabela temporária.
user4150760
5
Ah, é verdade, CONCURRENTLYnão economiza no tempo total de computação, apenas minimiza o tempo que sua visualização materializada fica indisponível para uso durante sua atualização.
Atualização simultânea (Postgres 9.4)
Embora não seja uma atualização incremental conforme solicitado, o Postgres 9.4 fornece um novo recurso de atualização simultânea .
Para citar o documento…
Esta atualização simultânea ainda está executando uma nova consulta completa (não incremental). Portanto, CONCURRENTLY não economiza no tempo total de computação, apenas minimiza o tempo que sua visualização materializada fica indisponível para uso durante sua atualização.
fonte
it instead creates a temporary updated version of it...compares the two versions
- Isso significa que a versão atualizada temporária ainda é uma computação completa e aplica a diferença à visualização existente. Então, essencialmente, ainda estou refazendo TODOS os cálculos, mas apenas na tabela temporária.CONCURRENTLY
não economiza no tempo total de computação, apenas minimiza o tempo que sua visualização materializada fica indisponível para uso durante sua atualização.