Eu tenho que atualizar tabelas de 1 ou 2 bilhões de linhas com vários valores para cada linha. Cada execução faz ~100 milhões de alterações (10%). Minha primeira tentativa foi agrupá-las em transações de 300K atualizações diretamente em uma partição específica, pois o Postgresql nem sempre otimiza as consultas preparadas se você usa partições.
- Transações de um monte de "UPDATE myTable SET myField=value WHEREmyId=id"
Dá 1.500 atualizações/seg. o que significa que cada execução levaria pelo menos 18 horas. - Solução de atualizações HOT conforme descrito aqui com FILLFACTOR=50. Fornece 1.600 atualizações/s. Eu uso SSDs, então é uma melhoria cara, pois dobra o tamanho do armazenamento.
- Inserir em uma tabela temporária de valor atualizado e mesclá-los depois com UPDATE...FROM dá 18.000 atualizações/seg. se eu fizer um VACUUM para cada partição; 100.000 up/s caso contrário. Legal.
Aqui está a sequência de operações:
CREATE TEMP TABLE tempTable (id BIGINT NOT NULL, field(s) to be updated,
CONSTRAINT tempTable_pkey PRIMARY KEY (id));
Acumule um monte de atualizações em um buffer dependendo da RAM disponível Quando estiver cheio, ou precisar mudar de tabela/partição, ou concluído:
COPY tempTable FROM buffer;
UPDATE myTable a SET field(s)=value(s) FROM tempTable b WHERE a.id=b.id;
COMMIT;
TRUNCATE TABLE tempTable;
VACUUM FULL ANALYZE myTable;
Isso significa que uma execução agora leva 1,5h em vez de 18h para 100 milhões de atualizações, incluindo vácuo. Para economizar tempo, não é necessário fazer um vácuo FULL no final, mas mesmo um vácuo regular rápido é útil para controlar seu ID de transação no banco de dados e não obter um vácuo automático indesejado durante as horas de pico.