← Voltar ao blog
    Banco de Dados8 min
    Como configurar a memória corretamente no PostgreSQL

    Como configurar a memória corretamente no PostgreSQL.

    Um PostgreSQL lento nem sempre precisa de mais CPU. Em muitos incidentes de produção, a causa está em uma configuração de memória que parecia conservadora, mas multiplica consumo por conexão, força o sistema operacional a usar swap e transforma consultas normais em disputa por recursos. Saber como configurar a memória corretamente no PostgreSQL é tratar capacidade, concorrência e risco operacional como variáveis do mesmo problema.

    Em uma operação transacional, não existe valor mágico para copiar de um blog ou aplicar indiscriminadamente em todos os servidores. Um banco com 64 GB de RAM, poucas conexões e consultas analíticas tem um comportamento completamente diferente de um ambiente com milhares de conexões, picos de pagamento e réplicas de leitura. A configuração correta começa pela carga real e termina com monitoramento contínuo.

    O erro mais caro: somar memória fixa e ignorar memória por operação

    O PostgreSQL usa memória de formas diferentes. Parte é compartilhada pela instância, parte é reservada por sessão e outra parte pode ser consumida repetidamente dentro de uma mesma consulta. Ignorar essa distinção é uma das causas mais frequentes de pressão de memória em produção.

    `shared_buffers` é memória compartilhada. Já `work_mem` não é uma reserva única para todo o banco: ele pode ser usado por cada operação de ordenação, hash, agregação ou materialização, em cada conexão. Consultas paralelas ampliam ainda mais esse cenário. Configurar 256 MB de `work_mem` porque o servidor tem bastante RAM pode ser aceitável para poucas sessões analíticas, mas é perigoso em uma API com centenas de conexões concorrentes.

    O cálculo que interessa não é apenas o valor do parâmetro. É a combinação entre `max_connections`, número efetivo de sessões ativas, plano de execução, paralelismo e comportamento da aplicação. Um incidente de falta de memória raramente avisa com antecedência. Ele começa com latência, aumenta a leitura em disco, aciona swap e pode terminar em encerramento de processos pelo sistema operacional.

    Como configurar a memória corretamente no PostgreSQL por camada

    A configuração precisa separar cache compartilhado, memória de trabalho, manutenção e capacidade do sistema operacional. Alterar tudo ao mesmo tempo elimina a possibilidade de identificar causa e efeito. O método seguro é ajustar, medir e documentar cada mudança.

    `shared_buffers`: cache do PostgreSQL, não toda a RAM disponível

    `shared_buffers` define a área de cache gerenciada pelo PostgreSQL. Como ponto de partida, ambientes dedicados frequentemente usam algo próximo de 20% a 30% da memória RAM. Isso não é uma regra absoluta. Em servidores com grande volume de dados, alta concorrência e sistema operacional moderno, deixar memória disponível para o cache de páginas do kernel é essencial.

    Alocar 70% ou 80% da RAM para `shared_buffers` normalmente não entrega ganho proporcional. Pelo contrário: reduz o espaço para o sistema operacional cachear arquivos, para processos auxiliares e para picos legítimos de memória de consulta. Em ambientes virtualizados ou em cloud, é obrigatório considerar o limite real imposto pela máquina virtual, pelo container ou pelo cgroup, e não a capacidade física do host.

    Esse parâmetro exige reinicialização do PostgreSQL. Portanto, qualquer mudança deve estar vinculada a uma janela controlada, plano de reversão e validação posterior.

    `effective_cache_size`: uma estimativa que muda o otimizador

    `effective_cache_size` não aloca memória. Ele informa ao planejador de consultas quanto cache provavelmente está disponível entre o `shared_buffers` e o cache do sistema operacional. Se o valor estiver muito baixo, o otimizador pode privilegiar planos menos eficientes, como varreduras sequenciais onde um índice seria adequado.

    Em um servidor dedicado, uma estimativa entre 50% e 75% da RAM costuma ser uma referência inicial razoável, desde que o valor reflita a memória realmente disponível após considerar outros serviços. O objetivo não é inflar o número. É dar ao planejador uma visão coerente da capacidade de cache existente.

    `work_mem`: o parâmetro que exige maior disciplina

    `work_mem` define a memória disponível antes que operações de sort e hash passem a gravar dados temporários em disco. Quando está baixo demais, aumentam os arquivos temporários, a latência e a atividade de I/O. Quando está alto demais para a concorrência existente, o servidor perde estabilidade.

    A configuração global deve ser deliberadamente conservadora em bancos OLTP. Depois, cargas específicas podem receber valores maiores no nível da sessão, do usuário ou da aplicação. Essa abordagem protege o tráfego transacional e oferece memória adicional para relatórios, ETLs e rotinas administrativas que realmente precisam dela.

    A evidência para esse ajuste está nos dados. Ative o registro de arquivos temporários com `log_temp_files`, analise consultas com `EXPLAIN (ANALYZE, BUFFERS)` e acompanhe métricas de escrita temporária. Se uma consulta crítica cria arquivos temporários grandes, aumentar `work_mem` apenas para aquela execução pode resolver o gargalo sem colocar toda a instância em risco.

    Memória de manutenção e autovacuum

    `maintenance_work_mem` atende operações como criação de índice, `VACUUM` manual e algumas tarefas de manutenção. Ele pode ter valor superior ao `work_mem`, pois essas operações são menos frequentes e normalmente planejadas. Ainda assim, índices grandes e operações simultâneas consomem recursos relevantes.

    Para o autovacuum, `autovacuum_work_mem` merece atenção específica. Quando fica com o valor padrão de `-1`, ele herda `maintenance_work_mem`. Isso pode ser inadequado em ambientes com diversos workers de autovacuum ativos. Se cada worker receber uma fatia grande de RAM, uma limpeza intensa pode competir com a carga de negócio. Definir um limite próprio para o autovacuum cria previsibilidade.

    Não trate autovacuum como uma tarefa secundária. Em tabelas transacionais, ele é parte da estratégia de disponibilidade. Memória insuficiente pode prolongar a manutenção; memória excessiva sem controle pode pressionar o servidor nos horários de maior tráfego.

    `temp_buffers` e `wal_buffers`: ajuste com propósito

    `temp_buffers` é reservado por sessão para tabelas temporárias. Em aplicações que usam esse recurso intensivamente, o parâmetro merece avaliação. Para a maioria dos ambientes, mexer nele antes de investigar planos, índices e uso de `work_mem` é desperdício de tempo.

    `wal_buffers` afeta o tratamento de WAL antes da gravação. O padrão automático funciona bem em muitos cenários. Ajustes manuais só fazem sentido após medir comportamento de checkpoints, volume de escrita e latência de armazenamento. Em banco crítico, parâmetros de WAL devem ser analisados junto de recuperação, réplica e objetivos de RPO e RTO, não isoladamente.

    A capacidade real depende de conexões, não do `max_connections`

    Aumentar `max_connections` para resolver erros de conexão é um remendo comum e caro. Cada backend do PostgreSQL tem custo de memória, além do consumo variável de `work_mem`, buffers e estruturas internas. Mil conexões abertas não significam mil usuários trabalhando, mas podem significar mil processos disputando recursos.

    O caminho mais seguro é limitar conexões no banco e usar pool de conexões na camada de aplicação. Com um pool bem dimensionado, centenas ou milhares de requisições podem ser atendidas por um número controlado de sessões no PostgreSQL. Isso reduz consumo de RAM, troca de contexto e instabilidade sob pico.

    Antes de definir limites, observe o histórico de `pg_stat_activity`: quantas conexões estão ativas, quantas permanecem ociosas em transação e quais serviços abrem sessões sem necessidade. Uma conexão `idle in transaction` não é apenas desperdício. Ela pode reter versões antigas de linhas, atrasar vacuum e criar efeitos em cadeia sobre armazenamento e performance.

    Um processo seguro de ajuste em produção

    A sequência correta começa pelo inventário: RAM efetivamente disponível, versão do PostgreSQL, topologia de réplicas, uso de pool, perfil de consultas, concorrência máxima observada e serviços coexistentes no host. Sem essa base, qualquer recomendação é palpite.

    Em seguida, estabeleça uma linha de base com consumo de memória do sistema, uso de swap, I/O de disco, arquivos temporários, latência das consultas mais relevantes e checkpoints. Só então ajuste um grupo de parâmetros por vez. Parâmetros que aceitam reload podem ser aplicados com menor impacto, mas exigem a mesma validação. Parâmetros que pedem restart devem entrar em mudança planejada.

    Após a alteração, compare o comportamento em períodos equivalentes de carga. Uma melhora isolada em benchmark não valida uma configuração se ela aumenta risco no pico comercial. O critério é previsibilidade sob concorrência, não apenas menor tempo de uma consulta executada sozinha.

    Sinais de que a memória está mal dimensionada

    Swap ativo durante carga normal, crescimento de arquivos temporários, reinícios de processos por falta de memória, alta latência sem saturação aparente de CPU e planos com operações de disco são sinais que exigem investigação. Nenhum deles confirma sozinho um diagnóstico, mas juntos indicam que a política de memória precisa ser revisada.

    Também vale desconfiar de configurações herdadas. Valores aplicados anos atrás, antes de migração para cloud, crescimento de base, mudança no ORM ou adoção de réplicas, frequentemente permanecem no `postgresql.conf` sem relação com a realidade atual. Produção crítica não pode depender de parâmetros históricos sem proprietário técnico.

    A HTI Tecnologia trata ajuste de memória como disciplina operacional: diagnóstico do consumo real, validação de concorrência, testes controlados e documentação de cada decisão. Em banco de dados, estabilidade não vem de aumentar números. Vem de saber exatamente qual processo pode consumir memória, em que volume e sob qual carga.

    A melhor configuração é aquela que mantém o PostgreSQL rápido quando a operação está sob pressão, sem trocar performance pontual por risco de indisponibilidade.

    Sua privacidade importa

    Utilizamos cookies e tecnologias semelhantes para melhorar sua experiência, personalizar conteúdo e analisar o tráfego do site, conforme a LGPD (Lei nº 13.709/2018). Você pode gerenciar suas preferências a qualquer momento.