¿Qué es VACUUM a nivel de página en PostgreSQL?
Cada vez que ejecutas un DELETE o UPDATE en PostgreSQL, las filas antiguas no desaparecen inmediatamente: quedan como "tuplas muertas" ocupando espacio hasta que VACUUM las limpia. En una startup SaaS con alto volumen de transacciones, este proceso puede marcar la diferencia entre una base de datos que escala sin problemas y una que colapsa bajo su propio peso.
El comando VACUUM no devuelve espacio al sistema operativo, sino que lo marca como reutilizable dentro de la misma tabla. Esto permite que nuevas filas ocupen ese espacio sin necesidad de asignar nuevas páginas de disco, optimizando el uso de almacenamiento sin bloquear operaciones concurrentes.
Line pointers: el ciclo de vida LPNORMAL, LPDEAD, LP_UNUSED
Cada fila en una tabla de PostgreSQL está rastreada por un line pointer (puntero de línea) que cambia de estado según el ciclo de vida de la tupla:
👥 ¿Quieres ir más allá de la noticia?
En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.
👥 Unirme a la comunidad- LP_NORMAL: Apunta a una tupla viva actualmente visible para las transacciones activas. Es el estado normal de una fila que está siendo usada.
- LP_DEAD: Apunta a una tupla muerta (eliminada o actualizada) que
VACUUMeventualmente reclamará. Estas filas ya no son visibles pero ocupan espacio físico. - LP_UNUSED: Indica un slot donde existía una tupla pero el puntero fue limpiado, típicamente después de una reorganización con
VACUUM FULL.
Entender estos estados es crucial porque el rendimiento de tu consulta depende directamente de cuántas tuplas LP_DEAD tiene que saltar el motor antes de encontrar datos válidos. En tablas con alta rotación (como logs de eventos o sesiones de usuario), este acumulado puede degradar consultas en un 30-50% si no se gestiona adecuadamente.
Visibility Map y Free Space Map: los mapas que optimizan VACUUM
PostgreSQL mantiene dos estructuras internas que hacen que VACUUM sea eficiente en producción:
Visibility Map (VM): Un bitmap por tabla que rastrea qué páginas contienen únicamente tuplas visibles para todas las transacciones activas y futuras. Cuando VACUUM encuentra una página marcada en el VM, la salta completamente porque sabe que no hay nada que limpiar. Esto reduce drásticamente el I/O en bases de datos maduras donde la mayoría de los datos son estables.
Free Space Map (FSM): Registra cuánto espacio libre hay disponible en cada página dentro de una tabla. Después de que VACUUM reclama espacio de tuplas muertas, actualiza el FSM para que nuevas inserciones sepan dónde hay huecos disponibles. Sin este mapa, PostgreSQL tendría que escanear páginas aleatorias buscando espacio, incrementando la latencia de escritura.
Ambos mapas son la razón por la cual VACUUM estándar puede ejecutarse en paralelo con operaciones de producción sin bloquear lecturas o escrituras.
VACUUM vs VACUUM FULL: diferencias críticas para producción
| Característica | VACUUM estándar | VACUUM FULL |
|---|---|---|
| Recuperación de espacio | Marca espacio como reutilizable (no devuelve al OS) | Compacta la tabla y devuelve espacio al OS |
| Tipo de lock | Lock mínimo, corre en paralelo con SELECT/INSERT/UPDATE/DELETE | Lock ACCESS EXCLUSIVE, bloquea TODAS las operaciones |
| Impacto en producción | Genera tráfico de I/O pero no bloquea | Lento, intensivo y bloquea producción completamente |
| Recomendación de uso | Default para mantenimiento rutinario | Solo para bloat severo (>50%) en ventanas de mantenimiento |
El error más común en startups es ejecutar VACUUM FULL pensando que están "optimizando" la base de datos, cuando en realidad están tomando la tabla fuera de línea durante minutos u horas. A menos que tu bloat supere el 50% y el rendimiento esté críticamente degradado, nunca uses VACUUM FULL en producción.
Impacto del database bloat en el rendimiento de tu SaaS
El bloat ocurre cuando las tuplas muertas se acumulan más rápido de lo que VACUUM puede limpiarlas, forzando al query planner a escanear más filas de las necesarias. Para un SaaS, esto se traduce en:
- Latencia incrementada: Las consultas
SELECTdeben filtrar entre tuplas vivas y muertas, aumentando el tiempo de respuesta para tus usuarios finales. - Costos de infraestructura: El uso de disco puede ser significativamente mayor que el tamaño real de los datos, inflando tu factura de cloud sin beneficio.
- Stalls de transacciones: Si una transacción de larga duración bloquea el avance del
oldest xmin,VACUUMno puede limpiar tuplas muertas y el bloat se acumula exponencialmente.
Según benchmarks de la comunidad, niveles de bloat por debajo del 50% son generalmente aceptables, pero cuando superan consistentemente ese umbral, el rendimiento comienza a degradarse de forma noticeable. Tablas con n_dead_tup > n_live_tup requieren atención inmediata.
¿Qué significa esto para tu startup?
Como CTO o founder técnico gestionando infraestructura SaaS, el mantenimiento de PostgreSQL no es opcional: es una ventaja competitiva. Una base de datos bien tuneada puede manejar 10x más tráfico con los mismos recursos.
Acciones concretas para implementar hoy:
- Monitorea tablas con alta rotación: Ejecuta esta consulta semanalmente para identificar problemas antes de que impacten producción:
SELECT relname, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
Si ves tablas donde n_dead_tup supera el 20% de n_live_tup, ajusta autovacuum_vacuum_scale_factor a 0.1 para esa tabla específica.
Tunea autovacuum para tablas críticas: Para tablas con alto volumen de INSERT/DELETE (logs, eventos, sesiones), configura:
autovacuum_vacuum_scale_factor = 0.1(trigger más frecuente)autovacuum_vacuum_cost_limit = 2000(permite limpieza más agresiva)autovacuum_vacuum_threshold = 50(mínimo por defecto, ajústalo según volumen)Evita transacciones de larga duración: Una sola transacción abierta por días puede bloquear todo el proceso de
VACUUM. Implementa timeouts de transacción en tu código y alerta cuando una transacción exceda 1 hora.Nunca uses VACUUM FULL en producción: Programa ventanas de mantenimiento mensuales si necesitas compactar tablas severamente bloated, pero comunícalo a tu equipo como downtime planificado. Mejor aún: prevén el bloat con autovacuum bien configurado.
Aprovecha mejoras de PostgreSQL 17+: Si estás en versión 17 o superior, el proceso de
VACUUMahora usa un árbol radix comprimido para almacenar IDs de tuplas muertas, mejorando la eficiencia de memoria en tablas grandes. Monitorea la nueva columnamemory usageenVACUUM VERBOSEpara detectar cuándo excedesmaintenance_work_mem.
Herramientas de monitoreo recomendadas:
pg_stat_progress_vacuum: Vista del sistema que muestra progreso en tiempo real, incluyendo el modo (normal,aggressive,failsafe) y quién inició el proceso (manual,autovacuum).- Extensión
pgstattuple: Proporciona medición precisa del porcentaje de bloat, aunque es resource-intensive. Úsala en ventanas de bajo tráfico. - Dashboards personalizados con métricas de
n_dead_tup,last_autovacuumypg_relation_sizepara alertar proactivamente.
La diferencia entre una startup que escala sin fricción y una que lucha contra su propia infraestructura a menudo está en estos detalles de mantenimiento que parecen menores hasta que es demasiado tarde.
Fuentes
- Vacuum at the Page Level
- PostgreSQL Documentation: VACUUM
- PostgreSQL Documentation: Routine Vacuuming
- Postgres Vacuum Explained: Autovacuum, Bloat and Tuning
- PostgreSQL 19: CommitFest 2026-01
👥 ¿Quieres ir más allá de la noticia?
En nuestra comunidad discutimos las tendencias, compartimos oportunidades y nos ayudamos entre emprendedores. Sin humo, solo acción.
👥 Unirme a la comunidad













