Como criar uma Dimension Degenerate com atributos rolantes em Modelação de Dados (Kimball)
Este tutorial mostra como criar uma Dimension Degenerate que suporta atributos rolantes (rolling attributes) em Modelação de Dados (Kimball), útil quando um identificador de transacção transporta pequenos atributos que mudam com frequência e não justificam uma dimensão separada. A técnica reduz junções e mantém a performance sem perder rastreabilidade.
Pré-requisitos
- Conhecimentos básicos de Modelação de Dados (Kimball) e star schema.
- Acesso a SQL (ex.: SQL Server, PostgreSQL ou equivalente) para testes.
- Exemplos de dados de transacções com atributos pequenos e mutáveis (ex.: estado curto, códigos rápidos).
Passo 1: Entender quando usar uma Dimension Degenerate com atributos rolantes
Uma Dimension Degenerate (DD) é um conjunto de atributos armazenados na fact table ou ligados ao facto por um identificador degenerate. Aqui queremos suportar «atributos rolantes»: pequenos valores que mudam frequentemente por transacção (ex.: estado curto, flags, códigos externos) que não justificam uma dimensão larga. Usamos a DD para evitar criar muitas dimensões pequenas e para acelerar queries agregadas.
Passo 2: Escolher atributos e definir regras de retenção
Identifique quais atributos são candidatos: geralmente são curtos (varchar/char), baixo número de valores distintos e com volatilidade elevada. Defina regras: quais atributos ficam na DD, qual a granularidade temporal (última versão por transacção, historial por evento) e período de retenção (ex.: 90 dias).
Passo 3: Modelar a estrutura no star schema
Existem duas abordagens comuns: (A) armazenar os atributos directamente na fact table como colunas degenerate; (B) criar uma tabela Dimension Degenerate separada com chave degenerate_id e ligar à fact via essa chave. A opção B mantém a fact mais compacta se houver vários atributos rolantes e várias versões por transacção.
-- 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)
);
Passo 4: Definir processo ETL/ELT para atributos rolantes
O processo deve inserir novas versões na dim_degenerate e actualizar ligações na fact conforme a regra (ex.: ligar sempre à versão mais recente ao fechar a transacção). Use merge/upsert para manter histórico com valid_from/valid_to ou sobrescrever quando não for necessário histórico.
-- 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)
Passo 5: Consultas e agregações: usar a DD eficientemente
Para relatórios, combine a fact com a dim_degenerate filtrando por attribute_key e janela temporal. Para performance, prefira ligar através de degenerate_id na fact quando possível; caso contrário, una por transaction_id + validade.
-- 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 o resultado
Valide que: (1) cada transacção tem a versão correcta do atributo (ver exemplos com data); (2) queries agregadas usam índices e são rápidas; (3) o volume de versões na dim_degenerate corresponde às expectativas (ex.: não há versões duplicadas). Testes simples: comparar contagens entre a fonte de eventos e a dim_degenerate, e verificar que a fact_sales aponta para o degenerate_id correcto.
Conclusão
Uma Dimension Degenerate com atributos rolantes reduz a complexidade quando há muitos atributos curtos e voláteis, preservando a performance e o historial quando necessário. Próximos passos: definir políticas de limpeza (purge), monitorizar cardinalidade e ponderar compressão/particionamento. Dica: comece com poucas chaves e valide as regras de retenção antes de generalizar para todas as transacções.