Eu tenho o PostgreSQL configurado principalmente como recomendado pelo pgtune, e as configurações são supostamente conservadoras. O PostgreSQL está usando mais memória para uma única conexão do que as configurações sugerem ser permitido, fazendo com que meu sistema Linux fique sem RAM. Aqui estão minhas configurações para um sistema com 64 GB de RAM:
# All set by pgtune...
default_statistics_target = 50
maintenance_work_mem = 5GB # ... except I increased this one...
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 32GB # ... and decreased this one
work_mem = 384MB
wal_buffers = 8MB
checkpoint_segments = 16
shared_buffers = 15GB
max_connections = 80
Postgres está executando uma UPDATE
consulta enorme agora usando o processo no topo:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21857 postgres 20 0 43.381g 0.042t 0.015t S 1.0 68.9 605:40.48 postgres
20623 postgres 20 0 15.475g 0.015t 0.015t S 0.0 24.3 64:25.95 postgres
20624 postgres 20 0 15.457g 7.021g 7.013g S 0.0 11.2 0:41.90 postgres
RES é ~ 42 GB para esse. Combinado com esses outros dois processos, isso faz com que ~ 64 GB de RAM sejam usados, então algo provavelmente está com falha na página. Não deveria ser menor ou igual a 32 GB por processo? Eu pensei que talvez o work_mem
não estivesse incluído effective_cache_size
(a documentação não o declara explicitamente), mas isso não poderia levar 10 GB de RAM por si só, a menos que eu tivesse 26 junções de uma vez, e eu tenho no máximo 4. Então, eu esperaria pelo o máximo de 34 GB RES para um processo. O que estou perdendo aqui?
Se a tabela que está sendo atualizada por sua enorme instrução UPDATE tiver restrições de chave estrangeira, ela enfileirará todas as linhas atualizadas para que possa validar a restrição no final da instrução UPDATE. Para manter essa fila, ela usará toda a memória necessária, independentemente das configurações
work_mem
ou de qualquer outra coisa. Provavelmente é para lá que seus 43 GB estão indo. Se você não tiver memória suficiente para lidar com isso, pode ser necessário dividir sua atualização em transações menores ou descartar a restrição e adicioná-la novamente mais tarde.Você provavelmente está contando demais a quantidade de memória realmente usada. A coluna "RES" relatada por
top
relatará a quantidade de memória compartilhada (aproximadamente, shared_buffers, com um pouco mais de bloqueios e outras sobrecargas) uma vez em cada processo que tocou nessa shared_memory.effective_cache_size
não têm efeito sobre o uso da memória.Para citar http://www.postgresql.org/docs/9.5/static/runtime-config-query.html :