Usando o PG 9.1 no Ubuntu 12.04.
Atualmente, leva até 24 horas para executarmos um grande conjunto de instruções UPDATE em um banco de dados, que estão no formato:
UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid
(Estamos apenas substituindo os campos dos objetos identificados pelo ID.) Os valores vêm de uma fonte de dados externa (ainda não no banco de dados de uma tabela).
As tabelas possuem vários índices e nenhuma restrição de chave estrangeira. Nenhum COMMIT é feito até o fim.
Leva 2h para importar um pg_dump
banco de dados inteiro. Parece uma linha de base que devemos razoavelmente atingir.
Com exceção da produção de um programa personalizado que, de alguma forma, reconstrói um conjunto de dados para a importação do PostgreSQL, existe alguma coisa que podemos fazer para trazer o desempenho UPDATE em massa mais próximo do da importação? (Essa é uma área que acreditamos que as árvores de mesclagem estruturadas em log lidam bem, mas estamos pensando se há algo que possamos fazer no PostgreSQL.)
Algumas ideias:
- descartando todos os índices que não são de ID e reconstruindo depois?
- aumentar os pontos de verificação, mas isso realmente ajuda a taxa de transferência sustentada a longo prazo?
- usando as técnicas mencionadas aqui ? (Carregue novos dados como tabela e "mescle" dados antigos em que o ID não foi encontrado nos novos dados)
Basicamente, existem várias coisas para tentar e não temos certeza do que são mais eficazes ou se estamos ignorando 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.
fonte
explain analyze
que está usando um índice para a pesquisa?Respostas:
Suposições
Como faltam informações no Q, assumirei:
COPY
saída, com um únicoid
por linha para corresponder à tabela de destino.Caso contrário, formate-o corretamente primeiro ou use as
COPY
opções para lidar com o formato.Isso significa que não há acesso simultâneo. Caso contrário, considere esta resposta relacionada:
Solução
Sugiro que você siga uma abordagem semelhante, conforme descrito no link da sua terceira bala . Com grandes otimizações.
Para criar a tabela temporária, existe uma maneira mais simples e rápida:
Um único grande
UPDATE
de uma tabela temporária dentro do banco de dados será mais rápido que as atualizações individuais de fora do banco de dados por várias ordens de magnitude.No modelo MVCC do PostgreSQL , um
UPDATE
meio para 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 a tabela inteira de qualquer maneira, seria mais rápido, em geral, criar uma nova tabela e excluir a antiga.Se você tiver RAM suficiente disponível, defina
temp_buffers
(apenas 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 da quantidade de RAM necessária, execute um teste com uma pequena amostra e use as funções de tamanho de objeto db :
Script completo
Carga simultânea
As operações simultâneas na tabela (que eu descartei nas suposições no início) aguardarão, quando a tabela estiver bloqueada no final e falharão assim que a transação for confirmada, porque o nome da tabela é resolvido imediatamente para seu OID, mas a nova tabela possui um OID diferente. A tabela permanece consistente, mas operações simultâneas podem receber uma exceção e precisam ser repetidas. Detalhes nesta resposta relacionada:
Rota UPDATE
Se você (tiver que) seguir o
UPDATE
caminho, descarte qualquer índice que não seja necessário durante a atualização e recrie-o posteriormente. É muito mais barato criar um índice em uma peça do que atualizá-lo para cada linha individual. Isso também pode permitir atualizações QUENTES .I descrito um procedimento semelhante utilizando
UPDATE
a esta resposta estreitamente relacionada no SO .fonte
DROP TABLE
tira umAccess Exclusive Lock
. De qualquer maneira, eu já listei o pré-requisito na parte superior da minha resposta:You can afford to drop and recreate the target table.
pode ajudar a bloquear a tabela no início da transação. Sugiro que você inicie uma nova pergunta com todos os detalhes relevantes da sua situação, para que possamos chegar ao fundo disso.CREATE TABLE tbl_new AS SELECT t.*, u.field1, u.field2 from tbl t NATURAL LEFT JOIN tmp_tbl u;
,LEFT JOIN
permitindo manter linhas para as quais não há atualização. Claro queNATURAL
pode ser alterado para qualquer válidoUSING()
ouON
.Se os dados puderem ser disponibilizados em um arquivo estruturado, você poderá lê-los com um invólucro de dados externo e executar uma mesclagem na tabela de destino.
fonte
MERGE
ainda não está implementado no PostgreSQL . As implementações em outros RDBMS variam bastante. Considere as informações da tag paraMERGE
eUPSERT
.