Usando o PostgreSQL 12, tenho o requisito de que alguns dados precisem ser "atualizados" a cada noite. Isso significa: O banco de dados precisa fazer alguns cálculos com base na data atual e gravar o resultado na tabela. Isso funciona em geral. No entanto, a maneira como funciona não é perfeita, ao que parece.
Basicamente, existe uma consulta PLV8 como esta:
FAÇA $$
var myData = plv8.execute('SELECT id FROM my_table');
for(let i = 0; < myData.length; i++) {
plv8.execute('SELECT my_function_which_refreshes_lots_of_data($1)',[myData[i].id);
}
$$ LANGUAGE plv8;
my_function_which_refreshes_lots_of_data
pega o id de um item e faz todo o trabalho. Isso precisa ser feito dessa maneira, porque o acionamento da atualização também precisa ser possível para linhas únicas às vezes.
O problema é que de alguma forma isso saiu do controle. Atualmente, a consulta é executada por mais de uma hora, ocupa 99% da memória, preenche o espaço de troca e fica a maior parte do tempo no status "D" - "suspensão do disco (ininterrupta)". A duração da consulta não é um problema, pois geralmente é executada durante a noite, acionada por um cronjob. No entanto, o consumo de memória e o status do processo (basicamente como um zumbi) é ou pode ser um problema.
Então, minha ideia foi: Até onde eu sei, o PostgreSQL mantém todas as alterações nas tabelas na memória enquanto a consulta é executada e as grava apenas no final. Seria possível acionar manualmente "gravar no disco o que você tem até agora e liberar a memória"?
Eu faria isso no meu código depois plv8.execute('SELECT my_function_which_refreshes_lots_of_data($1)',[myData[i].id);
. É claro que, se o processo travar ou qualquer outra coisa, isso resultaria em um estado inconsistente: parte dos itens seria processada por my_function_which_refreshes_lots_of_data
, enquanto o restante permaneceria como antes. No entanto, isso é melhor do que nenhum item sendo escrito. E definitivamente melhor do que uma consulta rodando por tanto tempo e consumindo toda a memória.
Eu sei que poderia de alguma forma tentar dividir a consulta no lado do cliente. No entanto, isso seria menos conveniente para mim por alguns motivos.
Não, o PostgreSQL não mantém as transações em andamento armazenadas em cache na memória. Eles são gravados no disco como de costume.
Tudo o que acontece no momento da confirmação é que o log de gravação antecipada (WAL) e o log de confirmação são liberados para o disco.
Portanto, você deve investigar mais para encontrar a causa da sobrecarga de E/S.
Linhas úteis de investigação são:
use
pg_stat_statements
compg_stat_statements.track = all
para localizar as instruções SQL que causam o carregamento.definido
track_io_timing = on
para ver quais consultas contribuem mais para a carga de E/S.verifique se cada chamada de função é executada em uma transação separada ou não.
Se sim, agrupe várias chamadas em uma única transação - talvez os muitos flushes de WAL estejam matando você.