Um product manager pede a receita por categoria e região do último trimestre, comparada com o mesmo trimestre de um ano atrás. No banco de dados de pedidos, isso significa juntar cinco tabelas, montar um calendário na hora e lembrar que os clientes mudam de região. Cada pergunta nova exige novos joins, e dois analistas chegam a dois números.
Um esquema estrela resolve isso remodelando os dados em torno de um processo de negócio: uma tabela fato de medições no centro e, ao redor, tabelas de dimensão que as descrevem. Este artigo projeta um esquema estrela de vendas passo a passo, da granularidade ao SQL, incluindo dimensões de mudança lenta, estrela versus floco de neve e data warehouses colunares.
O que é um esquema estrela
Um esquema estrela tem dois tipos de tabela:
- Tabelas fato registram medições de um evento de negócio, como uma linha de pedido: chaves estrangeiras para as dimensões mais medidas numéricas. São estreitas e longas.
- Tabelas de dimensão guardam o contexto, o quem, o quê, onde e quando: tabelas largas, planas e curtas de atributos de texto, como categoria ou região.
O Kimball Group, que deu nome a muitas dessas técnicas, descreve o esquema como tabelas fato ligadas a tabelas de dimensão por chaves primárias e estrangeiras. A orientação do Power BI da Microsoft resume o apelo de forma simples: tabelas de dimensão permitem filtrar e agrupar, tabelas fato permitem resumir.
Projete em quatro passos
O processo de design dimensional em quatro passos de Kimball são quatro decisões, nesta ordem:
- Escolher o processo de negócio: vendas no varejo, em lojas e em uma loja virtual.
- Declarar a granularidade: uma linha por linha de pedido, ou seja, um produto em um pedido. Kimball chama a granularidade de contrato vinculante, declarado antes de qualquer dimensão ou fato.
- Identificar as dimensões: data, produto, loja, cliente e promoção, cada uma com um valor por linha de pedido.
- Identificar os fatos: quantidade, preço unitário, desconto, valor líquido e custo, todos verdadeiros nessa granularidade.
Comece pela granularidade atômica, o nível mais baixo que a origem captura; os resumos saem das linhas atômicas, nunca o contrário. Nunca misture granularidades: um frete cobrado por pedido, mas armazenado em cada linha, é contado uma vez por linha. Distribua-o pelas linhas com uma regra de negócio, como Kimball aconselha, ou dê a ele sua própria tabela fato.
As tabelas do exemplo
| Coluna de fact_sales | Papel | Observações |
|---|---|---|
date_key |
Chave estrangeira | Chave inteligente como 20261120 |
product_key, store_key, customer_key, promotion_key |
Chaves estrangeiras | Inteiros substitutos |
order_number |
Dimensão degenerada | Sem tabela de dimensão por trás |
line_number |
Identidade da linha | Único junto com order_number |
quantity, discount_amount, net_amount, cost_amount |
Medidas aditivas | Somam em qualquer dimensão |
unit_price |
Medida não aditiva | Nunca some |
As dimensões são planas de propósito: dim_product traz marca, subcategoria e categoria em uma linha, e dim_store trata a loja virtual como mais uma loja com channel = 'online'. order_number é uma dimensão degenerada: o contexto do cabeçalho vive em outras dimensões, sobra só o número, que continua útil para agrupar carrinhos.
O preço unitário é a armadilha clássica: somado entre linhas, não significa nada, então divida partes aditivas, como em SUM(net_amount) / SUM(quantity).
Chaves substitutas e a dimensão de data
Cada dimensão recebe uma chave substituta, um inteiro sem significado atribuído em sequência a partir de 1, porque uma dimensão que acompanha histórico tem várias linhas por chave natural e as origens muitas vezes discordam sobre as chaves. Mantenha a chave natural (sku, store_code, customer_id) como atributo para rastrear as linhas até a origem.
A dimensão de data é a exceção: estável e previsível, então sua chave pode ter significado, como 20261120, o que também ajuda no particionamento. Filtre e agrupe pelos atributos dela (year, quarter, is_holiday), não por aritmética sobre a chave. Vinte anos são apenas cerca de 7.305 linhas (20 × 365,25).
Chaves estrangeiras do fato nunca devem ser nulas: uma chave nula tira a linha dos inner joins, e os totais encolhem em silêncio. Use linhas de dimensão padrão para valores desconhecidos ou não aplicáveis; aqui, promotion_key 0 significa «Sem promoção».
Dimensões de mudança lenta
O tipo de dimensão de mudança lenta (SCD) decide o que os relatórios mostram depois que um atributo muda:
| Tipo | Nome | Em uma mudança | Histórico mantido |
|---|---|---|---|
| 0 | Manter o original | O valor nunca muda | Somente o valor original |
| 1 | Sobrescrever | Atualizar a linha no lugar | Nenhum |
| 2 | Adicionar nova linha | Fechar a linha atual, inserir uma nova com nova chave | Completo |
| 3 | Adicionar novo atributo | Copiar o valor antigo para uma coluna prior_, sobrescrever |
Um valor anterior |
Os tipos 4 a 7 de Kimball acrescentam minidimensões e híbridos destes.
O tipo 2 é o carro-chefe. O cliente C-1042 muda de Austin para Denver em 20 de novembro de 2026:
| customer_key | customer_id | city | valid_from | valid_to | is_current |
|---|---|---|---|---|---|
| 1001 | C-1042 | Austin | 2024-03-14 | 2026-11-20 | false |
| 2417 | C-1042 | Denver | 2026-11-20 | 9999-12-31 | true |
As vendas anteriores mantêm a chave 1001 e continuam em Austin; as posteriores recebem 2417. A carga do fato escolhe a linha cujo intervalo contém a data do pedido (valid_from <= order_date < valid_to). A definição de tipo 2 de Kimball pede pelo menos uma data de vigência, uma data de expiração e um indicador de linha atual; um valid_to num futuro distante em vez de nulo mantém simples os filtros de intervalo. Os snapshots do dbt implementam o tipo 2 para você.
Para relatar todo o histórico pela cidade atual, faça join com a linha atual do mesmo customer_id. A captura de dados de mudança alimenta bem o tipo 2, porque cada atualização chega como um evento; veja o diagrama de change data capture.
Esquema estrela vs esquema floco de neve vs uma tabela única
| Esquema estrela | Esquema floco de neve | Uma tabela única | |
|---|---|---|---|
| Dados de dimensão | Uma tabela plana por dimensão | Cadeias normalizadas: produto, subcategoria, categoria | Copiados em cada linha do fato |
| Joins por consulta | Um por dimensão usada | Um por tabela de cada cadeia | Nenhum |
| Corrigir um atributo | Atualizar uma tabela de dimensão | Atualizar uma tabela da cadeia | Reescrever cada linha do fato afetada |
| Melhor para | A maioria dos data marts e modelos de BI | Raramente vale a pena para analytics | Um painel ou extração de ML, gerados a partir de uma estrela |
Kimball desaconselha dimensões em floco de neve: elas são mais difíceis de navegar para usuários de negócio, podem prejudicar o desempenho das consultas, e uma dimensão achatada guarda exatamente a mesma informação. A orientação do Power BI concorda.
Uma tabela única dispensa joins, e a compressão colunar mantém baratos os valores repetidos. O custo é a manutenção: correções viram reescritas e atributos novos viram reconstruções, então gere-a a partir da estrela.
Uma consulta que o modelo facilita
SELECT d.year_month,
p.category,
SUM(f.net_amount) AS revenue,
SUM(f.net_amount - f.cost_amount) AS gross_margin,
SUM(f.net_amount) / NULLIF(SUM(f.quantity), 0) AS avg_selling_price
FROM fact_sales AS f
JOIN dim_date AS d ON d.date_key = f.date_key
JOIN dim_product AS p ON p.product_key = f.product_key
JOIN dim_store AS s ON s.store_key = f.store_key
WHERE d.year = 2026
AND s.channel = 'online'
GROUP BY d.year_month, p.category
ORDER BY d.year_month, revenue DESC;
Todo join vai do fato a uma dimensão por uma chave inteira; os filtros ficam em atributos de dimensão e as somas em colunas do fato. Uma pergunta nova muda o WHERE e o GROUP BY, não os joins, e é por isso que as ferramentas de BI geram essas consultas com confiabilidade.
Desempenho em data warehouses colunares
Data warehouses colunares leem apenas as colunas que uma consulta usa, o que combina com uma tabela fato estreita, e dimensões pequenas fazem join barato: em um broadcast join, o BigQuery envia a tabela menor a cada worker. Com chaves INT64 e quantidades de 8 bytes lógicos e valores NUMERIC de 16, a consulta acima lê 64 bytes por linha de pedido do fato, cerca de 32 GB para 500 milhões de linhas, por mais larga que seja a tabela.
- Pode por data. Particione, agrupe ou ordene o fato por
date_key. O BigQuery poda partições quando a própria coluna de particionamento tem um filtro constante, então varreduras grandes também devem filtrardate_keycom constantes, não sódim_date.year. - Declare as chaves, mesmo sem imposição. O BigQuery usa chaves primárias e estrangeiras declaradas
NOT ENFORCEDpara eliminar e reordenar joins, e o Snowflake elimina joins para restrições marcadasRELY. Nenhum dos dois verifica os dados, e restrições violadas podem retornar resultados errados, então teste as chaves no pipeline. - Colocalize no Redshift. A orientação do Redshift é distribuir o fato e uma dimensão pela chave em comum, usar distribuição ALL em outras dimensões, ou deixar
AUTOescolher.
Esquemas estrela geralmente ficam na camada gold de uma arquitetura medallion; o diagrama de arquitetura de pipeline de dados mostra como os dados chegam lá, e ETL vs ELT onde as transformações rodam.
O diagrama do esquema estrela de vendas
Conteúdo do diagrama
- fact_sales
- dim_date
- dim_customer
- dim_product
- dim_promotion
- dim_store
- date_key
- customer_key
- promotion_key
- product_key
- store_key
Como ler:
- fact_sales no centro guarda cinco chaves estrangeiras, o
order_numberdegenerado,line_numbere cinco medidas. - Pés de galinha em cada linha: zero ou muitas linhas do fato numa ponta, exatamente uma linha de dimensão na outra. Os rótulos nomeiam as chaves de join.
- Os cartões azul-petróleo são dimensões, com dim_date em cima e as demais à esquerda e à direita.
- O cartão âmbar, dim_customer, mantém o histórico como SCD tipo 2.
- O bloco Markdown informa a granularidade e quais medidas você pode somar.
Como desenhar diagramas estrela com clareza
- Escreva a granularidade no diagrama. Os revisores perguntam por ela primeiro, e uma granularidade mal lida causa contagem em dobro.
- Ponha o fato no meio e cada dimensão a um salto. Uma linha entre duas dimensões é um floco de neve; desenhe-a de propósito ou achate.
- Marque os papéis das chaves: PK, FK, NK para chaves naturais e DD para dimensões degeneradas.
- Mostre o tipo de SCD nas dimensões que mantêm histórico.
- Deixe de fora jobs de carga, tabelas de staging e colunas pelas quais ninguém filtra.
- Desenhe um processo de negócio por diagrama. Quando tabelas fato compartilham dimensões conformes, acrescente uma matriz de barramento: processos nas linhas, dimensões nas colunas.
Veja o exemplo de diagrama ER para a notação de pé de galinha.
Monte no Archboard
- Entre com Google ou GitHub e crie um diagrama.
- Se as tabelas existirem, cole os comandos
CREATE TABLEdelas na ferramenta de SQL para diagrama ER, ou o DBML na ferramenta de DBML para diagrama ER, para obter um primeiro rascunho. - Adicione uma Entidade do pacote Entidade-relacionamento chamada fact_sales, um atributo por linha: cinco chaves marcadas FK, order_number marcado DD, line_number e depois as medidas. Dê a ela um destaque azul.
- Adicione mais cinco nós Entidade: dim_date acima do fato, dim_customer e dim_promotion à esquerda, dim_product e dim_store à direita. Marque as chaves substitutas como PK e as naturais como NK; use destaques azul-petróleo, âmbar para dim_customer.
- Conecte fact_sales a cada dimensão com pés de galinha, zero ou muitos no fato e exatamente um na dimensão, e rotule cada linha com sua chave.
- Adicione notas Texto do pacote Básico: uma legenda de chaves, a regra do SCD tipo 2, a chave de data inteligente, a linha de promoção padrão e a loja virtual.
- Adicione um bloco Markdown do pacote Básico abaixo do fato com a granularidade e as regras de aditividade.
O exemplo usa 7 nós de diagrama e fica dentro do plano Free.
Perguntas frequentes
O que é um esquema estrela em termos simples? Uma tabela fato central de medições, como valores de vendas, ligada a tabelas de dimensão que as descrevem, como data, produto e cliente. Desenhado, parece uma estrela.
Qual é a diferença entre uma tabela fato e uma tabela de dimensão? Uma tabela fato armazena medições de eventos em uma granularidade declarada, mais chaves estrangeiras. Uma tabela de dimensão armazena os atributos pelos quais você filtra e agrupa, como categoria ou região.
Qual é a diferença entre um esquema estrela e um esquema floco de neve? Uma estrela mantém cada dimensão em uma tabela plana; um floco de neve a normaliza em cadeias como produto, subcategoria e categoria. Estrelas precisam de menos joins e são mais fáceis de usar.
Um esquema estrela é normalizado? Não totalmente. As tabelas de dimensão são desnormalizadas de propósito, repetindo valores como nomes de categoria em cada linha de produto, enquanto a tabela fato continua estreita.
Esquemas estrela ainda importam em data warehouses colunares? Sim. Tabelas largas são varridas a baixo custo em engines colunares, mas uma estrela ainda dá a você um único lugar para corrigir um atributo, histórico por meio de dimensões de mudança lenta e respostas consistentes entre relatórios.