Guia prático: como recuperar uma tabela excluída no PostgreSQL usando point-in-time recovery sem downtime
Por Kevin Marcondes · Publicado em · Atualizado em · 9 min de leitura
Como recuperar uma tabela excluída no PostgreSQL usando point-in-time recovery sem downtime? A resposta é restaurar um servidor temporário até antes do DROP, extrair somente a tabela e dependências, e reintroduzi-las no banco de produção com bloqueios mínimos. Assim você valida os dados antes do swap e evita parar o ambiente principal.
Quando usar PITR para recuperar só a tabela
Use point-in-time recovery quando você tem backups base e WALs arquivados e precisa voltar a um estado anterior sem interromper o ambiente de produção. A ideia é restaurar para um servidor temporário, encontrar a versão boa da tabela e importar de volta.
Esse é exatamente o caminho de como recuperar uma tabela excluída no PostgreSQL usando point-in-time recovery sem downtime quando você precisa validar o dado e reduzir riscos antes do retorno ao banco principal.
- Você sabe (ou consegue estimar) o horário do DROP.
- Há base backup recente e archiving contínuo dos WALs.
- A tabela não é UNLOGGED (essas não entram em WAL).
- Você pode levantar uma instância temporária compatível.
Pré-requisitos e limitações do método
Sem archiving contínuo prévio, o PITR completo pode não ser possível. Também é essencial restaurar em versão major idêntica à produção para evitar diferenças de formato. Nunca rode o PITR no servidor de produção: sempre use um host/container temporário com armazenamento suficiente.
Backups e monitoramento recorrentes reduzem drasticamente o impacto de incidentes. Se você ainda não tem rotina sólida, avalie práticas de hardening e backup em servidores Linux em hardening, backup e monitoramento.
- wal_level=replica, archive_mode=on e archive_command configurados.
- Base backup disponível de antes do incidente.
- Espaço em disco para restaurar dados e WALs.
- Acesso aos arquivos de archive (ex.: NFS/S3/volume local).
- Mesma versão major do PostgreSQL entre produção e recuperação.
# postgresql.conf (produção)
wal_level = replica
archive_mode = on
archive_command = 'rsync -a %p /mnt/pg_wal_archive/%f'
max_wal_senders = 10
hot_standby = on
Passo 1 — Descobrir o instante exato do DROP
Defina um recovery_target_time seguro (logo antes da exclusão). Utilize logs de aplicação, auditoria, ferramentas de observabilidade e o fuso horário da instância. Preferencialmente, selecione alguns minutos antes do incidente para garantir que a tabela exista no ponto escolhido.
Erros comuns aqui envolvem fuso horário. Confirme o timezone atual do banco e converta o horário do incidente, se necessário.
- Cruze logs de app, auditoria e deploys recentes.
- Valide timezone para evitar restaurar para o horário errado.
- Considere margem de segurança de 2–5 minutos antes do DROP.
-- Confirme o timezone efetivo da instância
SHOW TimeZone;
Passo 2 — Restaurar um servidor temporário com PITR
Restaure um base backup de antes do incidente em um novo diretório de dados. Configure o restore_command para acessar os WALs arquivados e aponte o recovery_target_time. Ao iniciar, o Postgres reexecuta os WALs até o instante e promove a instância.
- Use versão major idêntica à produção.
- Pense na segurança: isole rede/credenciais do servidor temporário.
- Escolha storage rápido para acelerar a aplicação dos WALs.
# Exemplo (PostgreSQL 12+): diretório /pgdata_rec
# 1) Extraia o base backup
sudo -u postgres tar -xvf /backups/base_backup_before_drop.tar -C /pgdata_rec
# 2) Configure parâmetros de recovery
cat >> /pgdata_rec/postgresql.conf <<'EOF'
restore_command = 'cp /mnt/pg_wal_archive/%f %p'
recovery_target_time = '2026-09-30 14:23:00+00'
recovery_target_action = 'promote'
recovery_target_timeline = 'latest'
EOF
# 3) Sinalize o recovery
sudo -u postgres touch /pgdata_rec/recovery.signal
# 4) Inicie a instância temporária
sudo -u postgres pg_ctl -D /pgdata_rec -l /pgdata_rec/logfile start
# Acompanhe os logs até a promoção (instância pronta para leitura)
Passo 3 — Extrair a tabela e dependências do servidor recuperado
Com a instância temporária pronta, faça dump apenas da tabela e objetos associados (sequências e, se aplicável, tipos e funções dependentes). O formato custom (-Fc) facilita restaurações seletivas. Se a tabela for particionada, faça dump das partições necessárias também.
- Inclua sequências relacionadas para preservar valores.
- Revise dependências (views, materialized views, FKs).
- Para tabelas grandes, prefira rede local de alta vazão.
# Exemplo: recuperar public.pedidos e a sequência de ID
pg_dump -h 10.0.0.50 -U postgres -d appdb -Fc \
-t public.pedidos -t public.pedidos_id_seq \
-f /tmp/pedidos.dump
Passo 4 — Restaurar no banco de produção com bloqueios mínimos
Se a tabela não existe mais, a restauração é direta. Se ela foi recriada após o incidente, prefira restaurar para um nome temporário, validar e depois fazer troca atômica de nomes. Índices grandes podem ser recriados com CREATE INDEX CONCURRENTLY para reduzir bloqueio. Triggers e FKs exigem atenção especial.
- Restaure para tabela temporária quando houver tabela atual.
- Crie índices CONCURRENTLY fora de transação para menor impacto.
- A troca de nomes usa bloqueio curto (ACCESS EXCLUSIVE), normalmente imperceptível.
- Ajuste a sequência após importar os dados.
| Opção de restauração | Duração do bloqueio | Observações |
|---|---|---|
| Restauração direta (tabela não existe) | Baixa | Importa e usa; índices normais podem bloquear mais. |
| Restauração em tabela temporária + swap | Muito baixa | Permite validação e troca rápida por RENAME. |
| Índices CONCURRENTLY | Muito baixa | Crie antes do swap; não usar dentro de transação. |
# 1) Restaurar para uma tabela temporária
pg_restore -h prod-db -U postgres -d appdb -j 4 \
-t public.pedidos -t public.pedidos_id_seq /tmp/pedidos.dump \
--no-owner --no-privileges
# 2) Se a tabela atual existe, faça swap rápido
psql -h prod-db -U postgres -d appdb <<'SQL'
BEGIN;
-- Se necessário, solte chaves estrangeiras que apontam para a tabela antiga aqui, e recrie após o swap.
ALTER TABLE IF EXISTS public.pedidos RENAME TO pedidos_old;
ALTER TABLE public.pedidos RENAME TO pedidos_restaurada; -- caso o dump tenha recriado com o mesmo nome
ALTER TABLE public.pedidos_restaurada RENAME TO pedidos;
COMMIT;
-- 3) Ajuste sequência após a carga
SELECT setval('public.pedidos_id_seq', (SELECT COALESCE(MAX(id),1) FROM public.pedidos)+1, false);
SQL
Validação pós‑restauração e riscos comuns
Antes do swap (ou logo após, se não havia tabela), valide estrutura e contagens. Compare checks básicos com a instância temporária. Monitore locks e impacto na aplicação. Para investigar bloqueios e contenção em produção, veja práticas no guia de jobs e bloqueios em PostgreSQL: auditar e otimizar jobs cron.
- Comparar COUNT(*), MIN/MAX de chaves, e amostras aleatórias.
- Validar constraints e FKs (ativar/checar, se tiver desativado).
- Reaplicar grants e políticas de segurança (RLS) se existirem.
- Verificar sequences e rotinas de manutenção (VACUUM/ANALYZE).
-- Exemplos de checagens rápidas
SELECT COUNT(*) FROM public.pedidos;
SELECT MIN(id), MAX(id) FROM public.pedidos;
ANALYZE public.pedidos;
E se o archiving não estava ativo? Alternativas práticas
Sem archive_mode ligado e sem base backups, recuperar via PITR clássico pode ser inviável. Avalie: snapshots do sistema de arquivos anteriores ao incidente, restauração de backups do provedor de nuvem, ou recuperação a partir de uma réplica física que ainda não aplicou o DROP. Quando viável, restaure em instância separada e siga o mesmo processo de extração/importação da tabela.
- Snapshots de volume/VM anteriores ao incidente.
- Restauração em serviços gerenciados com PITR ativado.
- Réplica física atrasada (se existir) para extrair a tabela.
- Ferramentas de terceiros têm limitações e riscos.
Como evitar o próximo incidente: práticas e arquitetura
Implemente archiving contínuo, políticas de retenção e testes periódicos de restauração. Para reverter mudanças de schema com segurança, use versionamento de banco e pipelines de migração confiáveis: confira o guia de versionamento de banco de dados. Para reduzir ainda mais downtime, considere replicação lógica/CDC para swaps controlados em produção: veja a estratégia de migração zero‑downtime com CDC.
- Testes de restauração regulares (table‑level e cluster‑level).
- Retenção adequada de WAL conforme RPO/RTO do negócio.
- Alertas de archiving e espaço em disco.
- Migrações com rollback e janelas de feature flags.
Perguntas frequentes
Consigo recuperar apenas uma tabela com PITR no PostgreSQL?
Sim, mas indiretamente. Você faz PITR para um servidor temporário até antes do incidente e então exporta somente a tabela (e dependências) com pg_dump, importando de volta na produção com bloqueios mínimos.
E se eu não tinha archive_mode ligado ou base backups?
O PITR clássico não será possível. Tente restaurar um snapshot do sistema de arquivos, usar backups do provedor de nuvem ou extrair da réplica física se ela não aplicou o DROP. No futuro, ative archiving e rotinas de backup testadas.
A restauração sem downtime é realmente sem bloqueios?
Você evita parada do banco principal restaurando em instância separada. A importação pode exigir bloqueios breves (por exemplo, no RENAME). Em geral, o impacto é imperceptível se planejar índices e a troca de nomes corretamente.
Como lido com sequências associadas à tabela?
Inclua as sequências no dump e, após importar, ajuste com setval para alinhar o próximo valor ao MAX(id) da tabela. Assim você evita colisões ou violações de chave primária em inserções futuras.
Preciso usar a mesma versão do PostgreSQL na instância temporária?
Sim, utilize a mesma versão major para restaurar base backups e aplicar WALs. Diferenças de versão major podem impedir a recuperação ou introduzir incompatibilidades de formato e collation.
Como escolho o recovery_target_time correto?
Use logs de aplicação e auditoria para identificar o horário do DROP e recupere alguns minutos antes, considerando o timezone do servidor. Validar o ponto escolhido evita restaurar para um estado ainda inconsistente.
Precisa recuperar uma tabela agora com mínimo impacto?
Podemos avaliar seu cenário, definir o ponto de recuperação e conduzir a restauração segura em uma instância temporária, com validação e importação de baixo risco.
Falar sobre recuperação PITRVeja também
- Como recuperar estatísticas e índices corrompidos no PostgreSQL que deixaram consultas lentas
- API REST com spikes de latência por queries N+1 e GC no PHP — como diagnosticar e corrigir
- Erro 'Too many connections' no PostgreSQL durante pico de faturamento — guia prático de diagnóstico e correção
- Reduzir custos migrando Magento para OpenMage com plano de rollback e testes de aceitação