Eu quero atualizar tabelas (meus 20-30) com 10s de milhões de registros cada.
O problema é que está demorando muito para o processo de atualização e também nesse momento o uso da CPU também fica muito alto. Eu quero fazer de forma que não possa usar muita CPU durante o processamento dos dados. Se o tempo de processamento aumentar, não será um problema para mim, mas deve usar recursos limitados da CPU para processar (atualizar) a tabela. Estou usando o PostgreSQL como banco de dados e o sistema operacional do servidor é Linux.
Exemplo de consulta minha pode ser assim
UPDATE TEMP
SET CUSTOMERNAME =
( select customername from user where user.customerid = temp.customerid );
A primeira pergunta é: por que é importante não usar muito tempo de CPU? A consulta terá um gargalo em algum recurso; se você pudesse introduzir acesso ao disco adicional suficiente, o tempo de CPU usado por segundo diminuiria, mas isso seria realmente uma melhoria? Que recurso você prefere saturar? Entender por que você enfatizou isso pode ajudar a orientar as pessoas a fornecer uma resposta que você achará útil.
Conforme sugerido em um comentário, sua consulta pode ser executada mais rapidamente com uma junção em vez de uma subconsulta correlacionada. Algo assim:
Outra coisa importante a saber é se você deseja atualizar todas as linhas da tabela. Alguns dos valores já estão corretos? Nesse caso, você obterá um grande aumento de desempenho ao não atualizar as linhas que não precisam. Adicionar
AND temp.customername is distinct from user.customername
àWHERE
cláusula.Se você limitar o número de linhas atualizadas em cada instrução e
VACUUM ANALYZE
após cada UPDATE, evitará o inchaço da tabela. Se o objetivo do desejo de minimizar o tempo de CPU é evitar um impacto no desempenho em transações simultâneas, isso lhe daria a oportunidade de introduzir um pequeno atraso (na forma de umsleep
ou algo semelhante) antes de iniciar o próximoUPDATE
de um conjunto de linhas.Melhor ainda, por que você está armazenando as informações de forma redundante na tabela temporária, em vez de juntá-las quando necessário? (Às vezes há uma boa razão; muitas vezes não há.)
Se você seguir o conselho muito bom de kgrittn e ainda tiver problemas de desempenho, pode ser necessário executar a atualização em lotes. Você ainda executaria atualizações baseadas em conjunto, mas as limitaria aos primeiros 1.000 (ou qualquer número que funcione para você, usei de 500 a 50.000) registros que não correspondem e, em seguida, continuariam em loop até que todos estivessem concluídos.
Se houver um índice ativado
TEMP.CUSTOMERNAME
e você estiver atualizando uma parte significativa daTEMP
tabela, elimine esse índice antes da atualização e reconstrua-o depois.O PostgreSQL não tem como reduzir a quantidade de tempo de CPU que um processo pode usar. No Linux, você pode usar recursos do sistema operacional como o comando renice para fazer isso. Consulte Prioridades para obter mais informações e alguns exemplos.