(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como criar uma Fact table de tipo 'Event Stream' em Modelação de Dados (Kimball)

João Barros 27 de October de 2026 4 min de leitura

Este tutorial ensina como modelar uma Fact table do tipo "Event Stream" em Modelação de Dados (Kimball) para registar eventos transaccionais contínuos (logs, cliques, mensagens). Uma Event Stream fact table é útil para análises de comportamento, funnel, latência e séries temporais, permitindo agregar por tempo e dimensão.

Pré-requisitos

  • Conhecimentos básicos de Modelação de Dados (Kimball), star schema e conceitos de dimensões e fact tables.
  • Ambiente SQL (ex.: SQL Server, PostgreSQL ou Azure SQL) para criar tabelas e carregar dados.
  • Exemplo de fonte de eventos (CSV, stream ou tabela de staging) com timestamp, user_id, event_type e payload mínimo.

Passo 1: Definir o propósito e o grain da Event Stream Fact

Antes de criar tabelas, explique claramente o propósito: analisar eventos individuais (cada linha = 1 evento) com resolução temporal elevada. O grain define que cada registo representa um evento gerado num instante por um sujeito ou sistema. Isto evita ambiguidades na agregação.

Passo 2: Escolher as dimensões conformed e os atributos essenciais

Selecione dimensões necessárias para as análises: DimDate (tempo), DimUser, DimEventType e, se necessário, DimDevice ou DimSession. Não carregue payloads grandes na fact; guarde referências ou chaves para atributos detalhados em dimensões ou numa área de OneLake/Lakehouse.

Passo 3: Esquema físico da Event Stream Fact

Crie a estrutura mínima com chaves surrogate para dimensões, timestamp e medidas de contagem. Inclui colunas para event_id, event_ts, keys e medidas (event_value se aplicável). Exemplo SQL:

CREATE TABLE fact_event_stream (
  event_sk BIGINT IDENTITY(1,1) PRIMARY KEY,
  event_id VARCHAR(100),         -- id original do evento
  event_ts DATETIME2 NOT NULL,   -- timestamp do evento
  date_sk INT NULL,              -- FK para DimDate (date part)
  user_sk INT NULL,              -- FK para DimUser
  eventtype_sk INT NULL,         -- FK para DimEventType
  session_sk INT NULL,           -- FK opcional para DimSession
  event_value FLOAT NULL,        -- medida opcional
  raw_payload NVARCHAR(MAX) NULL -- só se necessário para debugging
);

Passo 4: População e enriquecimento (ETL/ELT)

Ao carregar, atribua as surrogate keys das dimensões. Se usar ELT, faça JOINs entre a staging de eventos e as dimensões conformed para obter as SKs. Mantenha o processo idempotente usando event_id como chave natural.

-- Exemplo simplificado (INSERT com lookup de chaves)
INSERT INTO fact_event_stream (event_id,event_ts,date_sk,user_sk,eventtype_sk,event_value)
SELECT s.event_id, s.event_ts, d.date_sk, u.user_sk, et.eventtype_sk, s.value
FROM staging_events s
LEFT JOIN dim_date d ON CAST(s.event_ts AS DATE) = d.calendar_date
LEFT JOIN dim_user u ON s.user_id = u.user_id
LEFT JOIN dim_eventtype et ON s.event_type = et.event_type
WHERE NOT EXISTS (
  SELECT 1 FROM fact_event_stream f WHERE f.event_id = s.event_id
);

Passo 5: Otimizações para alta cardinalidade e performance

Event streams geram muitos registos. Use partição por date_sk ou por event_ts (dia/mês) e índices nas colunas de lookup (event_ts, user_sk, eventtype_sk). Evite NVARCHAR(MAX) em produção; mantenha raw_payload separado num storage de logs ou OneLake.

Passo 6: Tratamento de eventos duplicados e ordenação

Defina política para duplicados: deduplicação por event_id e, em streams idênticos sem id, por (user_id,event_ts,event_type). Para ordenação temporal, use event_ts com precisão suficiente e, se necessário, uma coluna sequence_number gerada no produtor.

-- Deduplicação por combinação quando não há event_id
WITH candidate AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id, event_ts, event_type ORDER BY ingest_ts) rn
  FROM staging_events
)
INSERT INTO fact_event_stream (...) SELECT ... FROM candidate WHERE rn = 1;

Verificar o resultado

Valide que o grain está correcto e que não há duplicados. Exemplos de queries de verificação:

-- Contagem por dia
SELECT d.calendar_date, COUNT(*) total_events
FROM fact_event_stream f
JOIN dim_date d ON f.date_sk = d.date_sk
GROUP BY d.calendar_date
ORDER BY d.calendar_date DESC;

-- Checar duplicados
SELECT event_id, COUNT(*) c FROM fact_event_stream GROUP BY event_id HAVING COUNT(*) > 1;

Conclusão

Uma Event Stream fact table permite analisar eventos em detalhe e em escala — a chave é definir o grain, usar dimensões conformed, partição e deduplicação. Próximos passos: criar agregações pré-computadas (materialized views), ajustar retenção e integrar com Power BI ou ferramentas de streaming. Dica: comece por um conjunto reduzido de eventos e monitorize o crescimento da cardinalidade.