No post anterior da nossa série Guia de Sobrevivência: Backup e Manutenção no Postgres, nós entendemos o papel do MVCC e como o VACUUM padrão trabalha como um faxineiro silencioso, liberando espaço interno nas tabelas sem atrapalhar a sua aplicação.
Porém, existe um cenário clássico de desespero: o disco do servidor bateu 95% de uso, o VACUUM padrão foi rodado, mas o tamanho dos arquivos no sistema operacional não diminuiu nada (lembra que ele apenas reorganiza o espaço interno?). A tentação imediata de todo administrador é rodar o temido comando VACUUM FULL.
É aí que mora o perigo. O VACUUM FULL é um remédio extremamente amargo. Se você executá-lo em horário comercial sem entender o seu mecanismo, você pode travar a sua aplicação completamente.
Hoje, vamos entender a diferença brutal entre o VACUUM padrão e o FULL, o perigo por trás dos locks exclusivos e como sobreviver a esse cenário usando alternativas inteligentes.
O Mecanismo por baixo do pano: Como cada um trabalha
Para entender o perigo, precisamos ver como os dois comandos operam no nível do disco e do sistema de arquivos.
O VACUUM Padrão (Lazy Vacuum)
Ele passa pelas páginas existentes da tabela, remove as linhas mortas (dead tuples) e deixa aquele espaço livre para novos INSERTs. O arquivo físico no HD mantém o mesmo tamanho.
- Lock aplicado:
SHARE UPDATE EXCLUSIVE. Este lock impede que outras rotinas de manutenção (como umANALYZEou outroVACUUM) rodem ao mesmo tempo na tabela, mas permite que sua aplicação continue dandoSELECT,INSERT,UPDATEeDELETEnormalmente.
O VACUUM FULL (A Reconstrução Radical)
Ele não faz apenas uma limpeza. O VACUUM FULL cria um arquivo físico totalmente novo no disco, copia apenas as linhas vivas para dentro dele, remove o arquivo antigo e renomeia o novo. O espaço desperdiçado (Bloat) é finalmente devolvido para o sistema operacional.
- Lock aplicado:
ACCESS EXCLUSIVE. Este é o nível de lock mais pesado do PostgreSQL. Ele impede qualquer tipo de acesso à tabela.
O Perigo: O Lock Exclusivo na Prática
Imagine que a sua tabela pedidos tem 100GB de tamanho, mas 60GB são apenas lixo (Bloat). Você decide rodar o vacuumdb -f (FULL) nela.
No segundo em que o comando inicia, a tabela pedidos entra em estado de isolamento. Se a sua aplicação tentar rodar um simples SELECT * FROM pedidos WHERE id = 10, a query não vai responder. Ela vai entrar em uma fila de espera (waiting).
Conforme os segundos e minutos passam, centenas de requisições dos usuários começam a acumular na fila do Postgres tentando acessar a tabela travada. O pool de conexões do seu backend esgota, a aplicação começa a dar erro de Timeout e o seu sistema cai. Tudo isso enquanto o VACUUM FULL reconstrói o arquivo em background.
⚠️ O Segundo Perigo (Falta de Espaço): Como o
VACUUM FULLcria uma cópia da tabela antes de apagar a antiga, você precisa ter espaço em disco disponível para essa operação. Se a sua tabela tem 40GB de dados vivos e está inchendo o disco, você precisará de pelo menos mais 40GB livres temporariamente para que o processo termine. Se o disco lotar no meio do processo, a operação sofre rollback e você volta à estaca zero.
O Gancho: Quando o VACUUM FULL é realmente necessário?
Apesar dos riscos, o VACUUM FULL não é um comando inútil. Ele é necessário em cenários específicos:
- Janelas de Manutenção Agendadas: Quando você tem autorização para deixar o sistema fora do ar (ou em modo de manutenção) durante a madrugada e precisa recuperar espaço em disco urgentemente.
- Pós-Deletes Massivos: Se você acabou de expurgar 90% dos dados de uma tabela histórica gigantesca e sabe que aquela tabela nunca mais vai crescer tanto, o
VACUUM FULLvai encolher o arquivo definitivamente.
Rodando via CLI com o vacuumdb
Se você planejou a sua janela de manutenção e vai executar a ação, o utilitário de linha de comando correspondente é utilizando a flag -f:
Bash
vacuumdb -U postgres -h localhost -d meu_banco -f -t public.tabela_gigante -v
-f: Ativa o modoFULL.-t: Fortemente recomendado focar em uma tabela por vez para gerenciar o tempo de travamento.
A Alternativa Inteligente: pg_repack (Leitura Complementar)
E se você precisa devolver espaço para o sistema operacional, mas trabalha em um ambiente 24×7 que não pode se dar ao luxo de ter minutos ou horas de downtime?
A resposta do mundo real de engenharia e DevOps é uma ferramenta de terceiros chamada pg_repack.
O pg_repack é uma extensão do PostgreSQL que faz exatamente a mesma coisa que o VACUUM FULL (reconstrói a tabela de forma compacta e devolve o espaço para o HD), mas sem aplicar o lock exclusivo.
Como o pg_repack funciona?
- Ele cria uma tabela temporária para armazenar os dados novos.
- Cria um gatilho (trigger) na tabela original para capturar todos os
INSERTs/UPDATEs/DELETEsque a sua aplicação continuar fazendo em tempo real. - Copia as linhas vivas da tabela velha para a nova.
- Aplica os dados acumulados pela trigger.
- Em uma fração de segundo (quase imperceptível), ele troca as tabelas de lugar no catálogo do Postgres.
Se você tem essa extensão instalada no seu servidor, o comando via CLI substitui o vacuum pesado:
Bash
pg_repack -d meu_banco -t public.tabela_gigante
Resumo Comparativo: Qual remédio aplicar?
| Característica | VACUUM Padrão | VACUUM FULL | pg_repack (Extensão) |
| Trava Leituras e Escritas? | Não | Sim (Lock Total) | Não |
| Devolve espaço ao S.O.? | Não | Sim | Sim |
| Precisa de espaço extra? | Não | Sim (tamanho das linhas vivas) | Sim (tamanho das linhas vivas) |
| Quando usar? | Diariamente (Autovacuum / Cron) | Janelas de manutenção críticas | Produção 24×7 sob alta carga |
Conclusão
O VACUUM FULL deve ser tratado como um botão de emergência. Ele funciona perfeitamente, mas exige planejamento, validação de espaço em disco e, acima de tudo, o alinhamento de que a aplicação ficará indisponível durante o processo.
Agora que destrinchamos a limpeza física e o espaço em disco, precisamos falar sobre a mente do Postgres: o otimizador de consultas. No próximo post, vamos entrar no Bloco 4 e entender o comando vacuumdb --analyze e como ele impede que suas queries fiquem cegas e lentas da noite para o dia. Até lá!
Você já passou pelo susto de rodar um VACUUM FULL em produção e ver o sistema parar? Conhecia o truque do pg_repack? Conte sua história nos comentários!