Cómo crear una Dimension Degenerate con atributos rodantes en Modelado de Datos (Kimball)
Este tutorial muestra cómo crear una Dimension Degenerate que soporta atributos rodantes (rolling attributes) en Modelado de Datos (Kimball), útil cuando un identificador de transacción transporta pequeños atributos que cambian con frecuencia y no justifican una dimensión separada. La técnica reduce joins y mantiene el rendimiento sin perder trazabilidad.
Prerequisitos
- Conocimientos básicos de Modelado de Datos (Kimball) y star schema.
- Acceso a SQL (ej.: SQL Server, PostgreSQL o equivalente) para pruebas.
- Ejemplos de datos de transacciones con atributos pequeños y mutables (ej.: estado corto, códigos rápidos).
Paso 1: Entender cuándo usar una Dimension Degenerate con atributos rodantes
Una Dimension Degenerate (DD) es un conjunto de atributos almacenados en la fact table o ligados al hecho por un identificador degenerate. Aquí queremos soportar «atributos rodantes»: pequeños valores que cambian frecuentemente por transacción (ej.: estado corto, flags, códigos externos) que no justifican una dimensión amplia. Usamos la DD para evitar crear muchas dimensiones pequeñas y para acelerar consultas agregadas.
Paso 2: Elegir atributos y definir reglas de retención
Identifique qué atributos son candidatos: generalmente son cortos (varchar/char), bajo número de valores distintos y con alta volatilidad. Defina reglas: qué atributos quedan en la DD, cuál es la granularidad temporal (última versión por transacción, historial por evento) y periodo de retención (ej.: 90 días).
Paso 3: Modelar la estructura en el star schema
Existen dos enfoques comunes: (A) almacenar los atributos directamente en la fact table como columnas degenerate; (B) crear una tabla Dimension Degenerate separada con clave degenerate_id y enlazar a la fact vía esa clave. La opción B mantiene la fact más compacta si hay varios atributos rodantes y varias versiones por transacción.
-- Exemplo: criar Dimension Degenerate separada (PostgreSQL/SQL Server sintaxe genérica)
CREATE TABLE dim_degenerate (
degenerate_id BIGINT IDENTITY PRIMARY KEY,
transaction_id VARCHAR(50) NOT NULL,
attribute_key VARCHAR(50) NOT NULL,
attribute_value VARCHAR(200),
valid_from TIMESTAMP NOT NULL,
valid_to TIMESTAMP NULL
);
CREATE INDEX idx_deg_txn_key ON dim_degenerate(transaction_id, attribute_key, valid_from);
-- Fact table guarda degenerate_id (última versão ou referência por evento)
CREATE TABLE fact_sales (
sale_key BIGINT IDENTITY PRIMARY KEY,
sale_date DATE NOT NULL,
transaction_id VARCHAR(50) NOT NULL,
degenerate_id BIGINT NULL,
amount DECIMAL(18,2),
FOREIGN KEY (degenerate_id) REFERENCES dim_degenerate(degenerate_id)
);
Paso 4: Definir proceso ETL/ELT para atributos rodantes
El proceso debe insertar nuevas versiones en dim_degenerate y actualizar enlaces en la fact conforme a la regla (ej.: enlazar siempre a la versión más reciente al cerrar la transacción). Use merge/upsert para mantener historial con valid_from/valid_to o sobrescribir cuando no sea necesario historial.
-- Exemplo MERGE (SQL Server) para inserir nova versão e fechar anterior
MERGE INTO dim_degenerate AS target
USING (VALUES (@transaction_id, @attribute_key, @attribute_value, @now))
AS source(transaction_id, attribute_key, attribute_value, valid_from)
ON target.transaction_id = source.transaction_id
AND target.attribute_key = source.attribute_key
AND target.valid_to IS NULL
WHEN MATCHED AND target.attribute_value <> source.attribute_value
THEN UPDATE SET valid_to = source.valid_from
WHEN NOT MATCHED BY TARGET
THEN INSERT (transaction_id, attribute_key, attribute_value, valid_from)
VALUES (source.transaction_id, source.attribute_key, source.attribute_value, source.valid_from);
-- Depois, ajustar fact_sales.degenerate_id para apontar para a nova versão (poderá usar SELECT para obter degenerate_id recém-criada)
Paso 5: Consultas y agregaciones: usar la DD eficientemente
Para informes, combine la fact con la dim_degenerate filtrando por attribute_key y ventana temporal. Para rendimiento, prefiera enlazar mediante degenerate_id en la fact cuando sea posible; en caso contrario, únase por transaction_id + validez.
-- Exemplo: obter último attribute_value por venda
SELECT f.sale_key, f.amount, d.attribute_value
FROM fact_sales f
LEFT JOIN dim_degenerate d
ON f.degenerate_id = d.degenerate_id;
-- Ou, se não tiver degenerate_id, buscar por transaction_id e data
SELECT f.sale_key, f.amount, d.attribute_value
FROM fact_sales f
LEFT JOIN dim_degenerate d
ON d.transaction_id = f.transaction_id
AND d.valid_from <= f.sale_date
AND (d.valid_to IS NULL OR d.valid_to > f.sale_date)
AND d.attribute_key = 'status';
Verificar el resultado
Valide que: (1) cada transacción tiene la versión correcta del atributo (ver ejemplos con fecha); (2) las consultas agregadas usan índices y son rápidas; (3) el volumen de versiones en la dim_degenerate corresponde a las expectativas (ej.: no hay versiones duplicadas). Pruebas simples: comparar recuentos entre la fuente de eventos y la dim_degenerate, y verificar que la fact_sales apunta al degenerate_id correcto.
Conclusión
Una Dimension Degenerate con atributos rodantes reduce la complejidad cuando hay muchos atributos cortos y volátiles, preservando el rendimiento y el historial cuando es necesario. Próximos pasos: definir políticas de limpieza (purge), monitorizar cardinalidad y considerar compresión/particionamiento. Consejo: empiece con pocas claves y valide las reglas de retención antes de generalizar a todas las transacciones.