Configure shared_buffers, work_mem, effective_cache_size e checkpoints do PostgreSQL para servidores com muita RAM e NVMe, com pgtune e huge pages.
Para que serve
A configuração padrão do PostgreSQL foi pensada para rodar em qualquer máquina, inclusive com pouca memória. Em um servidor dedicado com 128 GB ou mais de RAM e NVMe, ela deixa desempenho na mesa. Este guia de tuning PostgreSQL mostra quais parâmetros mudar primeiro, com valores de partida, e como conferir se a mudança ajudou. Vale para PostgreSQL 15 a 18 no Debian 12/13 e Ubuntu 24.04.
Pré-requisitos
- Saber quanta RAM o PostgreSQL terá de fato. Se ele roda em uma VM do Proxmox, conte a RAM da VM, não a do servidor físico.
- Saber se o banco divide a máquina com outros serviços (aplicação, PHP, Java) e quanto eles consomem.
- Acesso ao usuário
postgrese uma janela para reiniciar o serviço (alguns parâmetros exigem restart).
1. Gere uma base com o pgtune
O pgtune calcula valores a partir da versão, RAM, CPUs, tipo de disco e tipo de carga (web, OLTP, data warehouse). Use o resultado como ponto de partida, não como verdade final. Em seguida, revise cada item com as explicações abaixo.
2. Parâmetros principais do tuning PostgreSQL
| Parâmetro | O que faz | Ponto de partida |
|---|---|---|
shared_buffers | Cache de páginas do próprio PostgreSQL. O restante do cache fica com o sistema operacional. | 25% da RAM disponível ao banco. Acima de 32–40 GB o ganho costuma ser pequeno. |
effective_cache_size | Não aloca nada: só informa ao planejador quanto cache (PostgreSQL + SO) existe, para ele preferir índices. | 50% a 75% da RAM disponível. |
work_mem | Memória por operação de ordenação/hash, por nó do plano e por conexão. Se faltar, a operação vai para arquivo temporário em disco. | 16–64 MB em OLTP com muitas conexões; mais em relatórios. |
maintenance_work_mem | Memória para VACUUM, CREATE INDEX, ALTER TABLE. | 1–2 GB. |
max_wal_size | Volume de WAL entre checkpoints. Valor baixo gera checkpoints frequentes e picos de escrita. | 8–16 GB em bancos com escrita intensa. |
random_page_cost | Custo estimado de leitura aleatória. O padrão 4 foi pensado para disco giratório. | 1.1 em SSD/NVMe. |
max_connections | Cada conexão é um processo. Muitas conexões ociosas desperdiçam memória. | Mantenha baixo (100–300) e use pool. Veja o artigo sobre PgBouncer. |
work_mem, e cada conexão faz o mesmo. Com 300 conexões e 256 MB, o pior caso passa de 75 GB. Prefira um valor global moderado e aumente só para sessões específicas: SET work_mem = '512MB'; antes de um relatório pesado, ou ALTER ROLE relatorios SET work_mem = '256MB';.3. Aplique a configuração
No Debian/Ubuntu, o postgresql.conf já inclui o diretório conf.d. Crie um arquivo separado, o que facilita revisões e upgrades. Exemplo para uma VM com 64 GB de RAM dedicada ao PostgreSQL 17, 16 vCPUs e disco em NVMe:
cat > /etc/postgresql/17/main/conf.d/90-tuning.conf <<'EOF'
shared_buffers = 16GB
effective_cache_size = 44GB
work_mem = 32MB
maintenance_work_mem = 2GB
max_wal_size = 16GB
min_wal_size = 2GB
checkpoint_completion_target = 0.9
random_page_cost = 1.1
effective_io_concurrency = 200
max_connections = 200
max_worker_processes = 16
max_parallel_workers = 8
max_parallel_workers_per_gather = 4
huge_pages = try
log_temp_files = 0
EOF
Troque 17 pela sua versão (pg_lsclusters mostra). Também é possível usar ALTER SYSTEM SET parametro = valor;, que grava em postgresql.auto.conf; evite misturar os dois métodos para o mesmo parâmetro, porque o auto.conf tem prioridade.
No PostgreSQL 18, effective_io_concurrency já vem com 16 e existe o novo io_method (padrão worker) para I/O assíncrono. Mantenha o padrão até medir; io_uring é uma opção a testar no Linux.
4. Configure huge pages (recomendado acima de 8 GB de shared_buffers)
Com shared_buffers grande, huge pages reduzem o consumo de memória da tabela de páginas e melhoram a estabilidade. Descubra quantas páginas são necessárias (PostgreSQL 15 ou mais novo), com o serviço parado ou já configurado:
sudo -u postgres /usr/lib/postgresql/17/bin/postgres \
-D /var/lib/postgresql/17/main \
-c config_file=/etc/postgresql/17/main/postgresql.conf \
-C shared_memory_size_in_huge_pages
Reserve um pouco mais que o valor retornado (ex.: retornou 8400, use 8500):
echo "vm.nr_hugepages = 8500" > /etc/sysctl.d/60-hugepages.conf
sysctl --system
grep HugePages_ /proc/meminfo
Com huge_pages = try, o PostgreSQL usa huge pages se houver e inicia normalmente se não houver. Depois de confirmar que funciona, você pode trocar para on para falhar alto caso a reserva suma.
5. Reinicie e confira
systemctl restart postgresql@17-main
sudo -u postgres psql -c "SELECT name, setting, unit, pending_restart
FROM pg_settings WHERE name IN ('shared_buffers','work_mem',
'effective_cache_size','max_wal_size','huge_pages');"
Se pending_restart aparecer como t, o parâmetro ainda não entrou em vigor. Parâmetros como work_mem e random_page_cost valem com um simples SELECT pg_reload_conf();; shared_buffers, max_connections e huge_pages exigem restart.
Como saber se funcionou
- Taxa de acerto de cache:
Em OLTP,SELECT datname, round(blks_hit*100.0/nullif(blks_hit+blks_read,0),2) AS hit_pct, temp_files, pg_size_pretty(temp_bytes) AS temp FROM pg_stat_database WHERE datname NOT LIKE 'template%';hit_pctacima de 99% é o esperado.temp_bytescrescendo rápido indicawork_memcurto para alguma consulta (olog_temp_files = 0registra quais). - Checkpoints: no PostgreSQL 17/18,
SELECT num_timed, num_requested FROM pg_stat_checkpointer;(em versões anteriores, as colunas ficam empg_stat_bgwriter). Senum_requestedfor muito maior quenum_timed, aumentemax_wal_size. - Memória do sistema:
free -hdeve mostrar folga e nenhum uso de swap crescente.
Problemas comuns
O PostgreSQL não sobe depois de aumentar shared_buffers
Veja journalctl -u postgresql@17-main e /var/log/postgresql/. Com huge_pages = on e reserva insuficiente, o serviço falha. Volte para try ou aumente vm.nr_hugepages.
O servidor começou a usar swap ou o OOM killer matou o postgres
Soma de shared_buffers + (conexões ativas × work_mem × operações) + outros serviços passou da RAM. Reduza work_mem, use pool de conexões e, em VM, desative o ballooning de memória.
Mudei os parâmetros e nada melhorou
Configuração não compensa consulta ruim ou índice faltando. Identifique as piores consultas com pg_stat_statements (artigo sobre monitorar banco de dados) e veja o artigo sobre índices. Lentidão que piora com o tempo pode ser bloat: veja autovacuum e bloat no PostgreSQL.
Perguntas frequentes
Posso colocar shared_buffers em 75% da RAM?
Não é recomendado. O PostgreSQL depende também do cache do sistema operacional, e um shared_buffers enorme faz os mesmos dados ficarem em cache duas vezes. 25% é a recomendação da documentação como ponto de partida.
O pgtune é confiável?
É um bom começo e segue as regras da documentação. Ele não conhece suas consultas; ajuste depois de observar o banco em produção.
Preciso reiniciar para mudar work_mem?
Não. Basta SELECT pg_reload_conf(); ou definir por sessão, usuário ou banco.
Qual o valor certo de random_page_cost em NVMe?
Valores entre 1.0 e 1.1 são os mais usados, porque a leitura aleatória em NVMe custa quase o mesmo que a sequencial.
Leitura complementar
- PostgreSQL: Resource Consumption
- PostgreSQL Wiki: Tuning Your PostgreSQL Server
- PostgreSQL: Managing Kernel Resources (huge pages)
Precisa de ajuda?
Se houver suspeita de problema de memória ou disco no servidor físico, abra um ticket com a saída de free -h, dmesg | tail -50 e a descrição do sintoma.
