8  Esquemas Dimensionales y Redundancia

En el capítulo anterior se definieron hechos, dimensiones, granularidad y aditividad. Ahora corresponde decidir cómo se estructuran físicamente las dimensiones alrededor del hecho: qué tan normalizadas están, cuánta redundancia se acepta y qué impacto real tiene esa decisión sobre el costo y la velocidad de consulta.

8.1 Esquema de Estrella

El esquema estrella consiste en una tabla de hechos central conectada directamente a varias dimensiones. Sus dimensiones suelen estar desnormalizadas (redundancia controlada) para reducir joins y optimizar consultas analíticas.

En el ejemplo académico, la dimensión estudiante incluye atributos como carrera y facultad en la misma tabla, lo que simplifica consultas típicas del estilo “promedio por carrera y por semestre”. El costo es aceptar repetición (por ejemplo, repetir “ciencias” como facultad en muchos registros).

Desde el punto de vista estructural, el modelo puede representarse así:

erDiagram

    HECHO_EVALUACION_ACADEMICA {
        int id_estudiante
        int id_asignatura
        int id_tiempo
        decimal calificacion
        int creditos
        int indicador_reprobado
    }

    DIMENSION_ESTUDIANTE {
        int id_estudiante
        varchar nombre
        varchar sexo
        varchar generacion
        varchar carrera
        varchar facultad
    }

    DIMENSION_ASIGNATURA {
        int id_asignatura
        varchar nombre_asignatura
        varchar tipo_asignatura
    }

    DIMENSION_TIEMPO {
        int id_tiempo
        varchar semestre
        int anio
        varchar periodo
    }

    HECHO_EVALUACION_ACADEMICA }o--|| DIMENSION_ESTUDIANTE : pertenece_a
    HECHO_EVALUACION_ACADEMICA }o--|| DIMENSION_ASIGNATURA : corresponde_a
    HECHO_EVALUACION_ACADEMICA }o--|| DIMENSION_TIEMPO : ocurre_en

En este esquema:

  • La tabla de hechos está al centro.
  • Todas las dimensiones se conectan directamente a ella.
  • No existen relaciones entre dimensiones.
  • La información jerárquica (por ejemplo, carrera → facultad) se almacena dentro de la misma dimensión.

8.2 Esquema de Copo de Nieve (Snowflake)

El esquema de copo de nieve normaliza las dimensiones en subdimensiones. Por ejemplo, separar “carrera” y “facultad” en tablas propias relacionadas jerárquicamente, evitando redundancia, pero aumentando joins y complejidad de consulta.

erDiagram

    HECHO_EVALUACION_ACADEMICA {
        int id_estudiante
        int id_asignatura
        int id_tiempo
        decimal calificacion
        int creditos
        int indicador_reprobado
    }

    DIMENSION_ESTUDIANTE {
        int id_estudiante
        varchar nombre
        varchar sexo
        varchar generacion
        int id_carrera
    }

    DIMENSION_CARRERA {
        int id_carrera
        varchar nombre_carrera
        int id_facultad
    }

    DIMENSION_FACULTAD {
        int id_facultad
        varchar nombre_facultad
    }

    DIMENSION_ASIGNATURA {
        int id_asignatura
        varchar nombre_asignatura
        varchar tipo_asignatura
    }

    DIMENSION_TIEMPO {
        int id_tiempo
        varchar semestre
        int anio
        varchar periodo
    }

    HECHO_EVALUACION_ACADEMICA }o--|| DIMENSION_ESTUDIANTE : pertenece_a
    HECHO_EVALUACION_ACADEMICA }o--|| DIMENSION_ASIGNATURA : corresponde_a
    HECHO_EVALUACION_ACADEMICA }o--|| DIMENSION_TIEMPO : ocurre_en

    DIMENSION_ESTUDIANTE }o--|| DIMENSION_CARRERA : estudia
    DIMENSION_CARRERA }o--|| DIMENSION_FACULTAD : pertenece

En este esquema:

  • La dimensión estudiante ya no almacena directamente la facultad.
  • Carrera y facultad se modelan como entidades independientes.
  • Se elimina redundancia.
  • Se incrementa el número de joins necesarios para consultas que involucren facultad.

8.2.1 Comparación conceptual

Aspecto Estrella Copo de nieve
Normalización Baja (desnormalizada) Alta
Redundancia Controlada Reducida
Número de joins Menor Mayor
Complejidad conceptual Más simple Más estructurada
Rendimiento OLAP Generalmente mejor Puede disminuir
Gobierno de datos Más flexible Más controlado

8.2.2 Lo mismo, en SQL

Con un dominio distinto (ventas), la diferencia entre ambos esquemas se ve directamente en la consulta:

-- Estrella: un solo join por dimensión
select
  d.anio,
  p.categoria,
  sum(f.importe) as ventas
from fact_ventas as f
join dim_fecha as d using (fecha_key)
join dim_producto as p using (producto_key)
group by d.anio, p.categoria;
-- Copo de nieve: dim_producto no tiene "categoria", hay que subir un nivel más
select
  d.anio,
  c.categoria,
  sum(f.importe) as ventas
from fact_ventas as f
join dim_fecha as d using (fecha_key)
join dim_producto as p using (producto_key)
join dim_categoria as c using (categoria_key)
group by d.anio, c.categoria;
Criterio Estrella Copo de nieve
Consultas Simples, pocas uniones Más uniones
Redundancia Mayor Menor
Mantenimiento Directo Más entidades y claves
Uso recomendado BI y autoservicio Jerarquías grandes o compartidas

8.3 Redundancia controlada: qué cuesta realmente desnormalizar

La comparación anterior suele quedarse en “el copo de nieve reduce redundancia”, como si repetir datos fuera automáticamente malo. En un almacén de datos columnar (Parquet, Delta, BigQuery, Snowflake) esa redundancia casi no cuesta lo que parece.

Un motor columnar no almacena cada valor de texto tal cual: aplica codificación por diccionario (cada valor distinto se guarda una sola vez y cada fila solo referencia un código corto) y run-length encoding (RLE) sobre columnas ordenadas o de baja cardinalidad. Si dim_producto tiene 500,000 filas y la columna categoria solo tiene 20 valores distintos, el motor no almacena “Electrónica” 25,000 veces: almacena el diccionario de 20 categorías una vez y, por fila, un índice de unos cuantos bits.

En la práctica esto significa que:

  • Guardar categoria directamente en dim_producto (estrella) cuesta, en almacenamiento, un orden de magnitud similar a guardar categoria_key (copo de nieve) — ambos terminan siendo, a nivel de disco, un entero pequeño por fila.
  • El ahorro de espacio que promete la normalización es, en un motor columnar moderno, marginal frente a lo que cuesta en 1990 con motores orientados a fila.
  • Lo que sí cambia entre ambos esquemas no es tanto el almacenamiento, sino el costo de consulta.

8.4 Costo de consulta: joins y motores en la nube

El argumento a favor de la estrella no es “ocupa menos espacio”, es “cada consulta hace menos trabajo”. Esto importa especialmente cuando las dimensiones no son pequeñas.

Considera una dimensión cliente con 5 millones de filas, normalizada como dim_cliente → dim_ciudad → dim_estado (jerarquía geográfica en copo de nieve) contra la misma dimensión desnormalizada donde estado vive directamente en dim_cliente.

Para responder “ventas totales por estado”:

  • Estrella: fact_ventas (100M filas) hace un solo join contra dim_cliente (5M filas), que ya trae estado.
  • Copo de nieve: fact_ventas hace join contra dim_cliente (5M filas), y ese resultado intermedio vuelve a hacer join contra dim_ciudad (5K filas) y luego contra dim_estado (32 filas).

El segundo camino no es más caro por las tablas pequeñas (dim_ciudad, dim_estado) — es más caro porque agrega etapas de shuffle sobre un resultado intermedio ya grande (la salida del primer join, del tamaño de fact_ventas). Cada hop adicional en la cadena de joins vuelve a mover ese volumen de datos por la red del clúster.

Esto se traduce directamente en costo facturable:

  • BigQuery cobra por bytes escaneados/procesados; más joins sobre resultados intermedios grandes significan más bytes movidos y más slots ocupados.
  • Snowflake cobra por tiempo de cómputo del warehouse (créditos); una cadena de joins más larga generalmente implica más segundos de warehouse activo para la misma pregunta.

Regla práctica: la redundancia de un esquema estrella es barata cuando vive en una dimensión (se paga una vez, al cargar). El costo de un join extra se paga en cada consulta, multiplicado por cuántas veces se ejecuta esa consulta al día. Por eso los data marts orientados a BI casi siempre prefieren estrella, y el copo de nieve se reserva para jerarquías muy grandes, compartidas entre muchos data marts, donde mantener una sola versión de la verdad importa más que el costo por consulta.

8.5 Esquema de Constelación (Fact Constellation / Galaxy Schema)

Cuando dos o más procesos de negocio comparten las mismas dimensiones, tiene sentido que compartan también las tablas físicas: eso es un esquema de constelación. En vez de una estrella aislada por proceso, varias tablas de hechos se conectan a un conjunto de dimensiones conformadas (misma clave, mismo grano, mismo significado en todos los hechos que la usan).

Retomando el dominio hospitalario: además de FACT_CANCELACION_CITA (una fila por cita programada), el hospital también factura por cada servicio prestado. En vez de crear dimensiones nuevas y redundantes para ese segundo proceso, se reutilizan DIM_FECHA, DIM_HOSPITAL, DIM_SERVICIO, DIM_PACIENTE y DIM_ASEGURADORA:

erDiagram

    FACT_CANCELACION_CITA {
        int appointment_key
        int fecha_key
        int hospital_key
        int servicio_key
        int paciente_key
        int aseguradora_key
        int cancelled_flag
        int no_show_flag
    }

    FACT_FACTURACION_HOSPITALARIA {
        int factura_key
        int fecha_key
        int hospital_key
        int servicio_key
        int paciente_key
        int aseguradora_key
        decimal monto_facturado
        decimal monto_cubierto
        decimal monto_paciente
    }

    DIM_FECHA {
        int fecha_key
        date fecha
        int mes
        int anio
    }

    DIM_HOSPITAL {
        int hospital_key
        string hospital_nombre
        string estado
    }

    DIM_SERVICIO {
        int servicio_key
        string servicio_nombre
        string especialidad
    }

    DIM_PACIENTE {
        int paciente_key
        int edad
        string genero
    }

    DIM_ASEGURADORA {
        int aseguradora_key
        string aseguradora_nombre
        string tipo
    }

    FACT_CANCELACION_CITA }o--|| DIM_FECHA : fecha
    FACT_CANCELACION_CITA }o--|| DIM_HOSPITAL : hospital
    FACT_CANCELACION_CITA }o--|| DIM_SERVICIO : servicio
    FACT_CANCELACION_CITA }o--|| DIM_PACIENTE : paciente
    FACT_CANCELACION_CITA }o--|| DIM_ASEGURADORA : aseguradora

    FACT_FACTURACION_HOSPITALARIA }o--|| DIM_FECHA : fecha
    FACT_FACTURACION_HOSPITALARIA }o--|| DIM_HOSPITAL : hospital
    FACT_FACTURACION_HOSPITALARIA }o--|| DIM_SERVICIO : servicio
    FACT_FACTURACION_HOSPITALARIA }o--|| DIM_PACIENTE : paciente
    FACT_FACTURACION_HOSPITALARIA }o--|| DIM_ASEGURADORA : aseguradora

Esto resuelve exactamente el tipo de redundancia más caro: sin dimensiones conformadas, cada equipo que construye un nuevo data mart terminaría creando su propia versión de “paciente” o “servicio”, con distinta granularidad, distintos códigos y sin forma de cruzar ambos hechos (“¿cuántas citas canceladas generaron facturación parcial de cualquier forma?”). Con dimensiones conformadas, ambos hechos son comparables y combinables por las mismas llaves.

8.6 Patrones de diseño para gestionar redundancia

Además de estrella, copo de nieve y constelación, hay patrones puntuales para decidir dónde vive cada dato — evitando tanto la redundancia descontrolada como los joins innecesarios.

Patrones para decidir dónde vive cada dato

La elección depende de qué se comparte, qué identifica al hecho, qué cambia y qué cardinalidad existe.

¿Qué problema de modelado se necesita resolver?

Dimensión conformada

Una dimensión común sirve a varios hechos con el mismo grano, llaves y reglas.

Reutilizar sin duplicar

Dimensión degenerada

El identificador permanece en el hecho porque no tiene atributos propios.

Evitar una tabla vacía

Junk dimension

Los indicadores de baja cardinalidad se agrupan como combinaciones en una dimensión.

Agrupar columnas dispersas

Role-playing dimension

Una dimensión física asume varios roles; por ejemplo, pedido, envío y pago sobre DIM_FECHA.

Reutilizar mediante alias

Mini-dimensión

Los atributos volátiles se separan para no versionar toda una dimensión grande.

Aislar cambios frecuentes

Tabla puente

Una relación muchos a muchos se representa sin duplicar filas de la tabla de hechos.

Preservar la cardinalidad
Menos redundancia descontrolada Menos joins innecesarios

El diagrama presenta seis patrones de diseño que equilibran la redundancia y la complejidad de consulta.

Dimensiones conformadas. Una misma dimensión (mismo grano, mismas llaves) reutilizada por varios hechos, como DIM_FECHA en el ejemplo anterior. Es la base de cualquier esquema de constelación y evita que cada data mart reinvente “cliente” o “producto” con reglas distintas.

Dimensiones degeneradas. Un atributo que identifica al hecho (folio de orden, número de ticket) pero que no tiene atributos propios que ameriten una tabla de dimensión. Se guarda como columna directa en la tabla de hechos en vez de crear una dimensión de una sola columna.

Junk dimensions. Varios indicadores booleanos o de baja cardinalidad (es_promocion, metodo_pago, canal) se combinan en una sola dimensión “basurero” con una fila por combinación posible, en vez de agregar media docena de columnas sueltas al hecho o crear media docena de dimensiones diminutas.

Role-playing dimensions. La misma tabla física de dimensión se usa varias veces con distinto significado — por ejemplo, DIM_FECHA referenciada como fecha de pedido, fecha de envío y fecha de pago dentro del mismo hecho, mediante alias en la consulta (fecha_pedido_key, fecha_envio_key, fecha_pago_key, todas apuntando a la misma DIM_FECHA).

Mini-dimensiones. Cuando algunos atributos de una dimensión grande cambian con mucha frecuencia (ingresos estimados de un cliente, score de riesgo) separarlos en una dimensión pequeña propia evita que esos cambios disparen versiones nuevas de SCD tipo 2 en toda la fila del cliente — tema que se retoma en el siguiente capítulo.

Bridge tables. Cuando la relación entre el hecho y una dimensión es de muchos a muchos (un estudiante con varias becas activas, un diagnóstico con múltiples médicos tratantes) una tabla puente resuelve la relación sin duplicar filas del hecho ni forzar una cardinalidad que no existe en el negocio.

8.7 Conclusión

Estrella, copo de nieve y constelación no son alternativas puramente estéticas: cada una mueve el costo de un lugar a otro (almacenamiento vs. cómputo por consulta vs. complejidad de mantenimiento). En un motor columnar moderno, la redundancia dentro de una dimensión suele ser la opción más barata. Lo que todavía no se ha cubierto es qué pasa cuando esas dimensiones cambian — un cliente se muda de ciudad, un producto cambia de categoría. Ese es el tema del siguiente capítulo: dimensiones lentamente cambiantes (SCD).