Guía práctica: cómo recuperar una tabla eliminada en Postgres con PITR sin downtime

Por · Publicado el · Actualizado el · 9 min de lectura

frontal de rack con unidades de servidor y luces de estado verdes
Primer plano de servidores en rack, adecuado para temas de copia de seguridad y recuperación. Foto: heladodementa / Pixabay

¿Cómo recuperar una tabla eliminada en PostgreSQL usando point-in-time recovery sin downtime? La solución es restaurar en un servidor temporal hasta justo antes del DROP, extraer solo la tabla y sus dependencias, y reintroducirlas en la base de producción con bloqueos mínimos. De este modo validas los datos antes del intercambio y evitas detener el entorno principal.

Cuándo usar PITR para recuperar solo la tabla

Usa point-in-time recovery cuando tienes backups base y WALs archivados y necesitas volver a un estado anterior sin interrumpir producción. La idea es restaurar en un servidor temporal, localizar la versión correcta de la tabla y exportarla de vuelta.

Este es exactamente el procedimiento para recuperar una tabla eliminada en PostgreSQL usando point-in-time recovery sin downtime cuando necesitas validar los datos y reducir riesgos antes de restaurar en el servidor principal.

  • Sabes (o puedes estimar) el horario del DROP.
  • Existe un base backup reciente y archivado continuo de WALs.
  • La tabla no es UNLOGGED (esas no entran en WAL).
  • Puedes levantar una instancia temporal compatible.

Precondiciones y limitaciones del método

Sin archivado continuo previo, el PITR completo puede no ser posible. También es vital restaurar en la misma versión major que la producción para evitar diferencias de formato. Nunca ejecutes el PITR en el servidor de producción: siempre usa un host/contenedor temporal con espacio de almacenamiento suficiente.

Backups y monitoreo periódicos reducen drásticamente el impacto de incidentes. Si aún no tienes una rutina sólida, evalúa prácticas de hardening y backup en servidores Linux en hardening, backup y monitorización.

  • wal_level=replica, archive_mode=on y archive_command configurados.
  • Base backup disponible anterior al incidente.
  • Espacio en disco para restaurar datos y WALs.
  • Acceso a los archivos de archive (por ejemplo: NFS/S3/volumen local).
  • Misma versión major de PostgreSQL entre producción y recuperación.
# 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

Paso 1 — Encontrar el instante exacto del DROP

Define un recovery_target_time seguro (poco antes de la eliminación). Usa logs de la aplicación, auditoría, herramientas de observabilidad y el huso horario de la instancia. Preferentemente, selecciona algunos minutos antes del incidente para asegurarte de que la tabla exista en el punto elegido.

Los errores comunes aquí están relacionados con el huso horario. Confirma el timezone actual del servidor y convierte el horario del incidente si hace falta.

  • Cruza logs de la app, auditoría y deploys recientes.
  • Valida el timezone para evitar restaurar en el horario incorrecto.
  • Considera una margen de seguridad de 2–5 minutos antes del DROP.
-- Confirme o timezone efetivo da instância
SHOW TimeZone;

Paso 2 — Restaurar un servidor temporal con PITR

Restaura un base backup anterior al incidente en un nuevo directorio de datos. Configura restore_command para acceder a los WALs archivados y apunta recovery_target_time. Al iniciar, Postgres aplicará los WALs hasta el instante indicado y promoverá la instancia.

  • Usa la misma versión major que producción.
  • Piensa en la seguridad: aisla red/credenciales del servidor temporal.
  • Elige storage rápido para acelerar la aplicación de 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)

Paso 3 — Extraer la tabla y dependencias del servidor recuperado

Con la instancia temporal lista, realiza un dump solo de la tabla y objetos asociados (secuencias y, si aplica, tipos y funciones dependientes). El formato custom (-Fc) facilita restauraciones selectivas. Si la tabla está particionada, incluye las particiones necesarias también.

  • Incluye secuencias relacionadas para preservar valores.
  • Revisa dependencias (views, materialized views, FKs).
  • Para tablas grandes, prefiere red local de alta capacidad.
# 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

Paso 4 — Restaurar en la base de producción con bloqueos mínimos

Si la tabla ya no existe, la restauración es directa. Si fue recreada después del incidente, mejor restaura con un nombre temporal, valida y luego realiza un intercambio atómico de nombres. Índices grandes pueden recrearse con CREATE INDEX CONCURRENTLY para reducir bloqueos. Triggers y FKs requieren atención especial.

  • Restaura a una tabla temporal cuando exista una tabla actual.
  • Crea índices CONCURRENTLY fuera de transacción para menor impacto.
  • El intercambio de nombres usa un bloqueo corto (ACCESS EXCLUSIVE), normalmente imperceptible.
  • Ajusta la secuencia después de importar los datos.
Opción de restauración Duración del bloqueo Observaciones
Restauración directa (tabla no existe) Baja Importa y usa; índices normales pueden bloquear más.
Restauración en tabla temporal + swap Muy baja Permite validación y un cambio rápido con RENAME.
Índices CONCURRENTLY Muy baja Crear antes del swap; no usar dentro de transacción.
# 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

Validación post‑restauración y riesgos comunes

Antes del intercambio (o inmediatamente después, si no había tabla), valida estructura y conteos. Compara comprobaciones básicas con la instancia temporal. Monitorea locks e impacto en la aplicación. Para investigar bloqueos y contención en producción, revisa prácticas en el guía de jobs y bloqueos en PostgreSQL: auditar y optimizar cron jobs.

  • Comparar COUNT(*), MIN/MAX de claves y muestras aleatorias.
  • Validar constraints y FKs (activar/verificar si fueron deshabilitados).
  • Reaplicar permisos y políticas de seguridad (RLS) si existen.
  • Verificar secuencias y rutinas de mantenimiento (VACUUM/ANALYZE).
-- Exemplos de checagens rápidas
SELECT COUNT(*) FROM public.pedidos;
SELECT MIN(id), MAX(id) FROM public.pedidos;
ANALYZE public.pedidos;

¿Y si el archivado no estaba activo? Alternativas prácticas

Sin archive_mode activado y sin base backups, recuperar vía PITR clásico puede ser inviable. Evalúa: snapshots del sistema de archivos previos al incidente, restauración de backups del proveedor cloud, o recuperación desde una réplica física que aún no aplicó el DROP. Cuando sea posible, restaura en una instancia separada y sigue el mismo proceso de extracción/importación de la tabla.

  • Snapshots de volumen/VM anteriores al incidente.
  • Restauración en servicios gestionados con PITR activado.
  • Réplica física retrasada (si existe) para extraer la tabla.
  • Herramientas de terceros tienen limitaciones y riesgos.

Cómo evitar el próximo incidente: prácticas y arquitectura

Implementa archivado continuo, políticas de retención y pruebas periódicas de restauración. Para revertir cambios de esquema con seguridad, usa versionado de bases de datos y pipelines de migración confiables: consulta la guía de versionado de bases de datos. Para reducir aún más el downtime, considera replicación lógica/CDC para swaps controlados en producción: revisa la estrategia de migración sin downtime con CDC.

  • Pruebas regulares de restauración (a nivel tabla y cluster).
  • Retención adecuada de WAL según RPO/RTO del negocio.
  • Alertas de archivado y de espacio en disco.
  • Migraciones con rollback y ventanas controladas (feature flags).

Preguntas frecuentes

¿Puedo recuperar solo una tabla con PITR en PostgreSQL?

Sí, pero de forma indirecta. Realizas PITR en un servidor temporal hasta antes del incidente y luego exportas únicamente la tabla (y dependencias) con pg_dump, importándola de vuelta en producción con bloqueos mínimos.

¿Y si no tenía archive_mode activado o base backups?

El PITR clásico no será posible. Intenta restaurar un snapshot del sistema de archivos, usar backups del proveedor cloud o extraer desde una réplica física si no aplicó el DROP. En el futuro, activa archivado y rutinas de backup probadas.

¿La restauración sin downtime es realmente sin bloqueos?

Evitas parar la base principal restaurando en una instancia separada. La importación puede requerir bloqueos breves (por ejemplo, en el RENAME). En general, el impacto es imperceptible si planificas índices y el intercambio de nombres correctamente.

¿Cómo manejo las secuencias asociadas a la tabla?

Incluye las secuencias en el dump y, tras importar, ajusta con setval para alinear el siguiente valor con el MAX(id) de la tabla. Así evitas colisiones o violaciones de clave primaria en futuras inserciones.

¿Debo usar la misma versión de PostgreSQL en la instancia temporal?

Sí, utiliza la misma versión major para restaurar base backups y aplicar WALs. Diferencias de versión mayor pueden impedir la recuperación o introducir incompatibilidades de formato y collations.

¿Cómo elijo el recovery_target_time correcto?

Usa logs de la aplicación y auditoría para identificar el horario del DROP y recupera algunos minutos antes, considerando el timezone del servidor. Validar el punto elegido evita restaurar a un estado aún inconsistente.

¿Necesitas recuperar una tabla ahora con mínimo impacto?

Podemos evaluar tu escenario, definir el punto de recuperación y ejecutar la restauración segura en una instancia temporal, con validación e importación de bajo riesgo.

Hablar sobre recuperación PITR

Ver también