Buenas prácticas de desnormalización
Documenta los invariantes que las columnas desnormalizadas deben preservar. Desnormaliza solo con evidencia, propiedad y detección de desviaciones, no porque las uniones se sientan lentas en desarrollo.
Cómo usar esta lista
- Por defecto, usa 3NF para OLTP; usa esta lista solo al proponer columnas redundantes o vistas materializadas.
- Cada elemento marcado debe aparecer en la descripción del PR de migración o en el ADR.
- Programa consultas de desviación en el monitoreo; genera una alerta cuando los invariantes se rompan.
- Reevalúa la desnormalización después de ajustar índices y cambios de hardware; las uniones pueden volver a ser baratas.
A - Evidencia y Alcance
- Demuestra el problema con
pg_stat_statementsyEXPLAIN (ANALYZE, BUFFERS). Sin desnormalización sin consultas "calientes" medidas. - Prueba primero con índices de cobertura en el esquema normalizado. Los índices de FK más columnas
INCLUDEa menudo eliminan la necesidad de desnormalizar. - Define la obsolescencia aceptable para copias de lectura. Las vistas materializadas necesitan un SLA de
max_stalenessdocumentado. - Mantén las tablas normalizadas como fuente de verdad. La desnormalización es derivada; debes poder recalcularla a partir de las tablas base.
- Limita la desnormalización a rutas de acceso específicas. Una consulta de panel no es una razón para desnormalizar la tabla de hechos principal globalmente.
B - Invariantes y Documentación
- Clasifica cada columna redundante: instantánea (snapshot) o espejo (mirror). Las instantáneas nunca se actualizan; los espejos necesitan trabajos de actualización.
- Agrega
COMMENT ON COLUMNpara cada campo desnormalizado. Indica el invariante en lenguaje claro y el equipo propietario. - Registra el mecanismo de actualización. Disparador, trabajo por lotes o programa
REFRESH MATERIALIZED VIEWcon el propietario de guardia. - Versiona las instantáneas JSONB cuando cambie la forma. Incluye
schema_versiondentro de los blobs de instantáneas. - Agrega SQL de detección de desviaciones al runbook. Compara la columna desnormalizada con la fuente; alerta sobre la discrepancia para los espejos.
C - Seguridad de Implementación
- Prefiere disparadores (triggers) o columnas generadas sobre escrituras duales dispersas en la aplicación. Menos rutas de código significan menos errores.
- Usa
NOT NULLen columnas de instantánea rellenadas en la inserción. Las instantáneas NULL parciales rompen las herramientas de finanzas y soporte. - Crea índices únicos antes de
REFRESH CONCURRENTLY. La actualización concurrente de MV falla sin un índice único. - Actualiza MVs pesadas fuera de horas pico o en réplicas. Los picos de IO en el primario afectan la latencia de OLTP.
- Planifica la migración de contrato para eliminar la desnormalización. Las columnas desnormalizadas sin fechas de puesta fuera de servicio se convierten en deuda permanente.
D - Gobernanza
- Requiere un segundo revisor para los PRs de desnormalización. El DBA o ingeniero de staff aprueba el invariante y el rollback.
- Rastrea las columnas desnormalizadas en un catálogo de esquemas. Los nuevos empleados deberían encontrar todos los campos redundantes en una sola consulta de documentación.
- Vuelve a probar después de las actualizaciones de versión principal. Los cambios en el planificador pueden hacer que las uniones normalizadas sean lo suficientemente rápidas como para eliminar la desnormalización.
- No desnormalices a través de límites de inquilinos sin
tenant_iden el invariante. El riesgo de fuga entre inquilinos aumenta. - Realiza un post-mortem de cada incidente de desviación. Convierte los invariantes rotos en reglas de linting o verificaciones de CI.
Preguntas frecuentes
¿Cuál es la diferencia entre desnormalización de instantánea y espejo?
Las instantáneas congelan los valores en un evento (precio en el momento de la compra). Los espejos intentan rastrear los datos de dimensiones en vivo y necesitan actualización cuando la fuente cambia.
¿Cómo debería verse un COMMENT ON COLUMN?
COMMENT ON COLUMN order_items.unit_price IS
'SNAPSHOT invariant: unit price at insert; source products.price';¿Con qué frecuencia debo ejecutar la detección de desviaciones?
Espejos: nocturnamente o cada hora dependiendo del SLA. Instantáneas: solo cuando las reglas de negocio cambian retroactivamente los datos fuente.
¿Es alguna vez necesaria la desnormalización?
Las instantáneas históricas (unit_price, tax_rate_at_sale) son requisitos de negocio, no trucos de rendimiento opcionales.
¿Cuál es el mayor error de desnormalización?
Tratar las columnas espejo como instantáneas: los informes muestran correos electrónicos de clientes obsoletos para siempre sin un trabajo de actualización.
¿Deberían las vistas materializadas reemplazar la desnormalización de columnas?
Prefiere MVs cuando muchas consultas comparten la misma agregación. Prefiere la desnormalización de columnas cuando una sola fila necesita campos de instantánea incrustados en escrituras OLTP.
¿Cómo puedo listar todas las columnas desnormalizadas?
Mantén una tabla denorm_registry o busca COMMENT ON COLUMN para las etiquetas SNAPSHOT / MIRROR en los archivos de migración.
¿Pueden las restricciones CHECK forzar la desnormalización?
Solo para reglas derivables (line_total = quantity * unit_price). Los espejos entre tablas necesitan disparadores o trabajos.
¿Cuándo debería eliminar la desnormalización?
Cuando EXPLAIN muestra que la ruta normalizada cumple con el SLO después de mejoras de índices o hardware durante dos trimestres consecutivos.
¿Cómo se relaciona esto con los almacenes de datos?
Los almacenes de datos desnormalizan por diseño. La desnormalización OLTP aún necesita invariantes porque las aplicaciones escriben las mismas filas de las que dependen las transacciones.
Relacionado
- Conceptos básicos de normalización - diseño normalizado de referencia
- Desnormalización intencional - patrones de implementación
- Vistas materializadas - mecánicas de actualización
- Buenas prácticas de modelado de datos - lista de revisión de modelado
Versiones de la pila: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x y PostGIS 3.5+.