⌘K

07 – VACUUM FULL vs VACUUM padrão: O remédio amargo que pode travar sua aplicação

Last updated

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 um ANALYZE ou outro VACUUM) rodem ao mesmo tempo na tabela, mas permite que sua aplicação continue dando SELECT, INSERT, UPDATE e DELETE normalmente.

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 FULL cria 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:

  1. 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.
  2. 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 FULL vai 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 modo FULL.
  • -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?

  1. Ele cria uma tabela temporária para armazenar os dados novos.
  2. Cria um gatilho (trigger) na tabela original para capturar todos os INSERTs/UPDATEs/DELETEs que a sua aplicação continuar fazendo em tempo real.
  3. Copia as linhas vivas da tabela velha para a nova.
  4. Aplica os dados acumulados pela trigger.
  5. 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ísticaVACUUM PadrãoVACUUM FULLpg_repack (Extensão)
Trava Leituras e Escritas?NãoSim (Lock Total)Não
Devolve espaço ao S.O.?NãoSimSim
Precisa de espaço extra?NãoSim (tamanho das linhas vivas)Sim (tamanho das linhas vivas)
Quando usar?Diariamente (Autovacuum / Cron)Janelas de manutenção críticasProduçã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!

Still stuck? How can we help? Get Help