Vacuum, autovacuum e bloat: causa #1 de DB morrendo
⏱ 13 min·⭐ 55 XP
Pré-requisitos (0/1)0%
- ⬜🔍 Índices avançados: B-tree, BRIN, GIN, GiST, partial, covering(Database Deep — Postgres Internals)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Diagnosticar bloat
🗺️ Por que a tabela cresce com o número de linhas estável
1 · Atualizar cria versão novaa antiga fica
Nenhuma atualização sobrescreve — é o que dá concorrência sem trava.
ACUMULA▼
2 · A versão antiga vira lixoquando ninguém mais a vê
Ela ocupa disco e é lida em varredura, deixando a consulta mais lenta.
LIMPA▼
3 · A limpeza recupera o espaçopara reuso interno
Ela marca o espaço como reutilizável — normalmente NÃO devolve disco ao sistema.
MAS▼
4 · Transação aberta bloqueia tudoa causa mais comum
A limpeza só remove o que nenhuma transação ainda pode ver. Conexão ociosa com transação aberta segura versões por horas.
AJUSTE▼
5 · Ajustar por tabelanão global
Tabela de escrita intensa precisa de limpeza mais agressiva que o padrão do servidor.
-- Tabelas com mais dead tuples
SELECT
schemaname, relname,
n_live_tup, n_dead_tup,
ROUND(n_dead_tup::numeric / NULLIF(n_live_tup, 0) * 100, 2) AS dead_pct,
last_autovacuum,
last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;
-- Extension pgstattuple (mais precisa)
CREATE EXTENSION pgstattuple;
SELECT * FROM pgstattuple('orders');
-- mostra tuple_count, dead_tuple_count, free_space, etcTuning autovacuum por tabela
-- Tabela hot (muitos updates): autovacuum mais agressivo
ALTER TABLE orders SET (
autovacuum_vacuum_scale_factor = 0.05, -- default 0.2
autovacuum_analyze_scale_factor = 0.02, -- default 0.1
autovacuum_vacuum_cost_delay = 10 -- ms entre chunks
);
-- Desliga autovacuum em tabela static (append-only arquivo)
ALTER TABLE immutable_logs SET (autovacuum_enabled = false);
-- Monitor: não autovacuum em 1h+ com muitos dead?
SELECT relname, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000 AND (last_autovacuum < now() - INTERVAL '1 hour' OR last_autovacuum IS NULL);Quiz rápido
O que causa o inchaço de tabela nesse modelo de concorrência?
pg_repack — compactação online
# Extensão + tool CLI (não built-in)
# Recria tabela sem lock exclusivo — trigger mantém consistência durante
pg_repack -h localhost -U postgres -d mydb -t orders
# Pré-requisitos: PRIMARY KEY, espaço em disk (cria cópia antes de swap)
# Alternativa: pg_squeeze (nativo PG13+ em algumas distros)⚠️
VACUUM FULL bloqueia > 1h em tabela grande. Use pg_repack em prod. Planeje window mesmo assim — usa ~2x espaço durante swap.
Perguntas frequentes
❓ Por que a tabela cresce mesmo apagando registro?
Porque no controle de versão a exclusão marca a linha como morta em vez de liberar espaço — e a recuperação é feita pela limpeza. Se a limpeza não dá conta do ritmo de alteração, o espaço morto acumula: é o inchaço, e ele torna toda varredura mais lenta.
❓ Como saber se a limpeza automática está atrasada?
Comparando linhas mortas com linhas vivas por tabela e olhando a última execução. Tabela com muita alteração e limpeza rara é a que incha. O sintoma indireto é consulta que fica progressivamente mais lenta sem mudança de código nem de volume aparente.
❓ Limpeza completa resolve o inchaço?
Resolve e trava a tabela pelo tempo todo da reescrita, o que a torna inviável em produção. As alternativas são reorganização concorrente por ferramenta específica, ou ajustar a limpeza automática para acompanhar o ritmo — que é a solução de causa, não de sintoma.
Fixando
Quiz rápido
Por que ajustar a rotina de recolhimento por tabela costuma ser necessário?
Quiz rápido
Quando a compactação online é preferível à reconstrução tradicional?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…