Usando PG 9.1 no Ubuntu 12.04.
Atualmente, leva até 24h para executarmos um grande conjunto de instruções UPDATE em um banco de dados, que são da forma:
UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid
(Estamos apenas sobrescrevendo campos de objetos identificados por ID.) Os valores vêm de uma fonte de dados externa (ainda não no banco de dados em uma tabela).
As tabelas têm um punhado de índices cada e nenhuma restrição de chave estrangeira. Nenhum COMMIT é feito até o final.
Demora 2h para importar um pg_dump
banco de dados inteiro. Esta parece ser uma linha de base que devemos razoavelmente visar.
Além de produzir um programa personalizado que de alguma forma reconstrói um conjunto de dados para o PostgreSQL reimportar, há algo que possamos fazer para aproximar o desempenho do UPDATE em massa ao da importação? (Esta é uma área que acreditamos que as árvores de mesclagem estruturadas em log lidam bem, mas estamos nos perguntando se há algo que possamos fazer no PostgreSQL.)
Algumas ideias:
- descartando todos os índices não-ID e reconstruindo depois?
- aumentando checkpoint_segments, mas isso realmente ajuda a sustentar a taxa de transferência de longo prazo?
- usando as técnicas mencionadas aqui ? (Carregar novos dados como tabela e, em seguida, "mesclar" dados antigos onde o ID não é encontrado em novos dados)
Basicamente, há um monte de coisas para tentar e não temos certeza de quais são as mais eficazes ou se estamos negligenciando outras coisas. Passaremos os próximos dias experimentando, mas pensamos em perguntar aqui também.
Eu tenho carga simultânea na tabela, mas é somente leitura.
Suposições
Como as informações estão faltando no Q, vou assumir:
COPY
saída, com um exclusivoid
por linha para corresponder à tabela de destino.Caso contrário, formate-o corretamente primeiro ou use
COPY
as opções para lidar com o formato.Isso significa que não há acesso simultâneo. Senão, considere esta resposta relacionada:
Solução
Eu sugiro que você siga uma abordagem semelhante, conforme descrito no link do seu terceiro marcador . Com grandes otimizações.
Para criar a tabela temporária, existe uma forma mais simples e rápida:
Um único grande
UPDATE
de uma tabela temporária dentro do banco de dados será mais rápido do que atualizações individuais de fora do banco de dados em várias ordens de magnitude.No modelo MVCC do PostgreSQL , um
UPDATE
meio de criar uma nova versão de linha e marcar a antiga como excluída. Isso é tão caro quanto umINSERT
e umDELETE
combinado. Além disso, deixa você com muitas tuplas mortas. Como você está atualizando toda a tabela de qualquer maneira, seria mais rápido criar uma nova tabela e descartar a antiga.Se você tiver RAM suficiente disponível, defina
temp_buffers
(somente para esta sessão!) alto o suficiente para manter a tabela temporária na RAM - antes de fazer qualquer outra coisa.Para obter uma estimativa de quanta RAM é necessária, execute um teste com uma pequena amostra e use funções de tamanho de objeto db :
Roteiro completo
Carga simultânea
Operações simultâneas na tabela (que eu descartei nas suposições no início) vão esperar, uma vez que a tabela é bloqueada perto do final e falham assim que a transação é confirmada, porque o nome da tabela é resolvido para seu OID imediatamente, mas a nova tabela tem um OID diferente. A tabela permanece consistente, mas as operações simultâneas podem receber uma exceção e precisam ser repetidas. Detalhes nesta resposta relacionada:
ATUALIZAR rota
Se você (teve que) seguir a
UPDATE
rota, elimine qualquer índice que não seja necessário durante a atualização e recrie-o posteriormente. É muito mais barato criar um índice de uma só vez do que atualizá-lo para cada linha individual. Isso também pode permitir atualizações HOT .Eu descrevi um procedimento semelhante usando
UPDATE
nesta resposta intimamente relacionada no SO .Se os dados puderem ser disponibilizados em um arquivo estruturado, você poderá lê-lo com um wrapper de dados externo e realizar uma mesclagem na tabela de destino.