Pedir diagnóstico

BI e engenharia de dados

Por que um modelo de dados dos anos 1990 continua sendo a resposta para juntar mídia, analytics e pedido

A receita apareceu 2,02 vezes maior sem que ninguém vendesse mais e sem que nenhuma consulta estivesse errada. O que estava errado era o modelo — e o conserto tem quase trinta anos de idade.

Bruno Chipelo · Mídia, medição e engenharia de dados 12 de agosto de 2026 12 min de leitura · 2.418 palavras Parte 1 de 2 · Engenharia de dados aplicada a marketing

01 O sintoma

A receita que dobrou sem ninguém vender mais

A primeira versão de um painel de e-commerce mostrava uma receita 2,02 vezes maior que a reconhecida pelo financeiro. Nenhuma consulta estava errada. A soma pegava exatamente a coluna que tinha sido pedida e devolvia o total correto daquela coluna, linha por linha.

A tabela estava no grão de item — uma linha por produto dentro de cada pedido — e a coluna somada era o valor total do pedido, com frete e desconto, que a fonte repete em todas as linhas do mesmo pedido. Um pedido de três itens carrega o mesmo total três vezes. Somar aquela coluna não soma receita: soma o valor do pedido tantas vezes quantos itens ele tiver. O fator 2,02 não era um bug; era a média de itens por pedido daquela operação.

O que torna esse erro caro não é o tamanho, é a plausibilidade. Uma receita quarenta vezes maior alguém contesta na primeira reunião. O dobro passa: cabe num mês bom, numa data comercial, numa campanha que acabou de subir. E ele só apareceu porque havia uma segunda fonte para o mesmo fato — sem ela, o número seguiria sendo usado para decidir verba. Modelo dimensional é, antes de tudo, a disciplina que impede esse tipo de soma de ser escrita.

Este texto explica o vocabulário que impede a soma errada — fato, dimensão, grão e aditividade —, mostra as cinco decisões que ele tomou por nós numa operação real, o que essas decisões custaram, e termina nas duas verificações que precisavam passar antes de qualquer consulta usar o modelo.

02 O conceito

Fato, dimensão, grão: o vocabulário que evita a soma errada

Fato e dimensão

Um modelo dimensional separa o que se mede do que descreve a medida. Fato é o que se soma: valor, quantidade, custo, clique, sessão. Dimensão é o contexto pelo qual se corta: o dia, o produto, a campanha, o cliente, o canal, a página. A tabela de fatos guarda os números e as chaves; as tabelas de dimensão guardam os atributos que dão sentido a eles.

A separação parece burocracia até a primeira pergunta nova chegar. Numa planilha em que tudo mora na mesma aba, "receita por categoria de produto no fim de semana" é uma coluna a mais, feita à mão, que passa a existir só naquele arquivo. Num modelo dimensional é um GROUP BY por outra dimensão — a pergunta muda, o dado não. O desenho radial que sai disso, uma tabela de fatos no centro cercada pelas dimensões, é o que dá nome ao star schema.

Os quatro passos, e por que o segundo é o caro

Kimball descreve o projeto dimensional em quatro passos, sempre nesta ordem: escolher o processo de negócio, declarar o grão, escolher as dimensões e identificar os fatos. O primeiro é mais sutil do que parece — processo de negócio é um evento que a operação de fato executa (um pedido faturado, um clique cobrado, uma sessão do site), não um relatório que alguém quer ver. Modelar em cima do relatório produz uma tabela que responde àquela pergunta e a nenhuma outra.

O segundo passo é o caro. Grão é o que uma linha significa, dito numa frase, antes de qualquer coluna existir: "uma linha por item dentro de um pedido", "uma linha por campanha por dia". É a única decisão do projeto sem volta barata. Agregar para cima é um GROUP BY; descer é impossível, porque o detalhe que não foi gravado não existe em lugar nenhum. Daí a regra prática: guardar sempre no grão mais fino que a fonte entrega, mesmo quando nenhuma pergunta atual precisa desse detalhe.

Aditividade

Declarado o grão, cada medida precisa de uma segunda declaração: por quais dimensões ela pode ser somada. São três casos.

Aditivo
soma por qualquer dimensão. Investimento, quantidade vendida, cliques: somar por dia, por campanha, por produto e por região sempre devolve algo verdadeiro.
Semi-aditivo
soma por algumas dimensões, nunca por tempo. Estoque e saldo são o exemplo clássico: somar o estoque de dois depósitos faz sentido, somar o estoque de segunda com o de terça não faz — ali o correto é a foto do último instante.
Não aditivo
não soma por nenhuma. Toda razão entra aqui: retorno sobre investimento, taxa de conversão, ticket médio, custo por aquisição. A regra é recalcular do numerador e do denominador dentro do balde. Média de médias é o erro mais comum de painel, e ele fica pior quanto mais desiguais forem os baldes.

O sintoma do começo é exatamente uma aditividade não declarada. O valor total do pedido é aditivo no grão de pedido e deixa de ser no grão de item — a mesma coluna muda de natureza quando o grão muda debaixo dela. Nomear isso no modelo é o que transforma um erro silencioso numa regra que se escreve uma vez.

-- errado: o total do pedido se repete em cada item
SELECT SUM(valor_total_pedido) FROM fato_venda;

-- receita de pedido: colapsa para o grão do pedido antes de somar
SELECT SUM(valor_total_pedido) FROM (
  SELECT DISTINCT pedido_id, valor_total_pedido FROM fato_venda
);

-- receita de item: some a coluna que vive no grão da linha
SELECT SUM(valor_item) FROM fato_venda;
Duas consultas sobre a mesma tabela no grão de item. A primeira soma a receita tantas vezes quantos itens o pedido tiver.

Dimensão conformada

Uma dimensão é conformada quando serve a mais de um fato com o mesmo significado e as mesmas chaves. O calendário é o caso mais evidente: o mesmo dia, com a mesma definição de semana, atende o fato de mídia, o fato de sessão do site e o fato de pedido. É o que faz duas telas pararem de discordar sobre a mesma semana — e o que permite pôr investimento e receita, que vêm de sistemas diferentes, lado a lado sem inventar equivalência.

A ferramenta de planejamento que Kimball dá para isso é a bus matrix: uma grade com processos de negócio nas linhas e dimensões nas colunas, marcando quais dimensões cada fato usa. Ela cabe numa página e é o que revela, antes de qualquer código, que "campanha" significa duas coisas diferentes em duas fontes.

Por que isso encaixa em dados de marketing

Uma operação de mídia razoavelmente instrumentada tem quatro famílias de fonte, e nenhuma delas concorda com as outras em três pontos ao mesmo tempo. A plataforma de anúncio entrega custo no grão de campanha por dia, no fuso da conta, com a régua de atribuição que ela mesma define. O analytics do site entrega sessão e evento, com outra régua e frequentemente outro fuso. O e-commerce entrega pedido e item, no fuso da loja, com status que muda depois. A ferramenta de busca entrega consulta por página por dia, com atraso de alguns dias e amostragem própria.

O modelo dimensional não faz essas fontes concordarem — isso não é possível, porque elas medem coisas diferentes. Ele faz a discordância virar algo localizável: cada fato guarda a medida da sua própria fonte, todas apontam para as mesmas dimensões, e a comparação passa a acontecer numa dimensão comum, com a régua declarada. É a diferença entre "os números não batem" e "o custo vem da plataforma, a receita vem do pedido, e a diferença entre as duas leituras de conversão é esta".

Três tabelas de fatos ligadas às mesmas dimensões No centro, três tabelas de fatos: mídia no grão de campanha por dia, sessões no grão de dia por origem e vendas no grão de pedido por item. Dos dois lados, quatro dimensões compartilhadas: calendário, campanha, produto e canal. Cada dimensão se liga às três tabelas de fatos pela mesma chave. fato · mídia campanha × dia fato · sessões dia × origem fato · vendas pedido × item dim · calendário dia, semana, −364d dim · campanha nome, tipo, objetivo dim · produto categoria, linha dim · canal origem, mídia a mesma dimensão serve os três fatos
Três fatos, cada um no seu grão, compartilhando as mesmas dimensões. Nenhum deles precisa concordar com os outros: a comparação acontece na dimensão comum.

03 Como aplicamos

Cinco decisões que esse modelo tomou por nós

A escolha do grão

Num varejo de catálogo largo, na casa das dezenas de milhares de pedidos por ano, a base de vendas foi gravada em pedido × item, e não em pedido. No grão de pedido não existe resposta para "qual produto vendeu" — que é metade das perguntas de um painel de e-commerce — e a volta para o grão de pedido continua sendo um GROUP BY. A tabela ficou maior; o conjunto de perguntas possíveis ficou muito maior.

A chave que descarta em silêncio

A primeira versão da chave dessa tabela foi nossa e estava errada: pedido + produto. Parece suficiente até aparecer o pedido em que o mesmo produto ocupa duas linhas — um brinde a custo zero e uma unidade paga. A chave colapsa as duas em uma, e o carregamento não reclama: ele grava a segunda por cima da primeira e segue. Não há erro, não há aviso, e a linha simplesmente deixa de existir. A correção é acrescentar o índice da linha à chave. Uma centena de pedidos tinha esse formato — o suficiente para mexer no ranking de produto e em nada mais, que é justamente o tipo de defeito que ninguém procura.

O total repetido

A coluna de valor total do pedido continua existindo na tabela, porque ela responde perguntas que a soma dos itens não responde (frete e desconto de pagamento moram nela). O que passou a existir junto é a regra escrita: para receita de pedido, agregue por pedido; para receita de item, some a coluna do item. Não é documentação por gosto de documentar — é a única defesa contra alguém somar a coluna certa no grão errado daqui a um ano.

A dimensão de calendário como porta de entrada

O calendário é a dimensão mais barata que existe: algumas centenas de linhas por ano, sem dependência de fonte externa. Também é a que quase ninguém cria — a data fica sendo um campo do fato, e cada consulta reimplementa o que precisa dela. Num mesmo projeto encontramos seis implementações independentes de "somar N dias" e três de "que dia da semana é este". Nenhuma estava errada. O problema é que a próxima correção chega a uma delas, e a divergência não estoura: ela mente.

O que a dimensão passou a carregar, uma vez só, para todo mundo: o deslocamento de 364 dias — 52 semanas exatas — em vez de 365, porque comparar com o ano anterior sem alinhar o dia da semana coloca sábado contra sexta e produz uma variação que é do calendário, não do negócio; feriado móvel calculado a partir da Páscoa, e não chumbado numa lista, porque lista fixa envelhece sozinha e a base degrada para "dia útil" sem avisar; e uma regra de precedência declarada num lugar só — fim de semana vence feriado, de modo que um domingo se comporta como domingo mesmo sendo feriado.

A fronteira que a dimensão não atravessa

A mesma dimensão entrega o número do dia da semana, não o nome. Dois painéis do mesmo grupo escreviam coisas diferentes: um usava "Segunda-Feira" com a semana começando na segunda, o outro usava "Dom" começando no domingo. Conformar o rótulo obrigaria uma das duas telas a mudar de cara por um motivo que não é dela. Rótulo é decisão de apresentação; a dimensão conformada existe para garantir que as duas estejam falando do mesmo dia, não para uniformizar como cada uma o chama.

04 Trade-offs

O que este modelo custa, e quando não vale a pena

Um texto que só descreve o benefício de uma escolha está descrevendo outra coisa. Três decisões desse projeto foram contra o manual, de propósito.

Não normalizar o fato

Cidade, estado e origem do pedido continuam dentro da tabela de fatos, como texto, em vez de virarem dimensões próprias com chave. O livro-texto pediria a separação. Em dezenas de milhares de linhas por dia, ela custa join em toda consulta e devolve um ganho de espaço que ninguém sente. Fato largo é o padrão certo nesse porte — e a decisão se inverte quando o volume cresce uma ou duas ordens de grandeza, ou quando o atributo passa a mudar no tempo e exigir histórico.

Chave natural em vez de sintética

A chave das tabelas é a natural — o identificador do pedido, a data no formato ISO — e não um inteiro sequencial. A chave sintética economizaria bytes que sobram e cobraria em legibilidade justamente na hora em que se está depurando, com o banco aberto às onze da noite. A troca compensa em ambiente com muitas dimensões que mudam de valor no tempo; não compensa aqui.

Arquitetura medalhão, como contraste de porte

A divisão em bronze, prata e ouro popularizada pelo mundo lakehouse pressupõe engine distribuída, armazenamento barato em objeto e um time para operar tudo isso. Num banco de borda que processa dezenas de milhares de linhas por dia, materializar três cópias do mesmo dado adiciona latência e superfície de erro sem resolver problema nenhum que exista ali.

O que se aproveita dela é a ideia de camadas: pouso cru, conformado, servido — que no nosso caso são um esquema, uma rotina de normalização e uma consulta, não três bancos. O que não se aproveita é a física. Dizer em que porte ela passa a valer — quando o volume não cabe mais numa máquina, quando há mais de um time escrevendo na mesma base, quando o custo de reprocessar do zero supera o de manter cópias — é mais útil, e mais honesto, que descartá-la como modismo.

05 Como provamos

Duas afirmações verificáveis

Modelo bom não é o que convence numa apresentação; é o que sobrevive a uma verificação que poderia tê-lo reprovado. Duas rodaram sobre a dimensão de calendário antes de qualquer consulta passar a usá-la.

A dimensão bate com o código que já estava em produção

A coluna de semana, a de data do ano anterior e a de dia da semana foram comparadas, sobre toda a série, com as funções que o sistema já usava em produção — as mesmas seis implementações espalhadas que motivaram a dimensão. Resultado: zero divergência. Isso não prova que a dimensão está certa em algum sentido absoluto; prova que trocar as seis por ela não muda um único número exibido hoje. É essa a pergunta que importa numa substituição, e é a que quase nunca é feita.

O join não deixa órfã

A falha clássica de uma dimensão de data é a série de fatos passar da última linha da dimensão. O join interno começa a descartar os dias novos em silêncio, o gráfico simplesmente termina mais cedo, e ninguém associa o buraco à tabela que expirou. A checagem é contar os fatos cuja data não encontra correspondência na dimensão. Foi medida em milhões de linhas de fato: nenhuma órfã.

Essas duas contagens rodam de novo a cada carga. É o que permite escrever, sem adjetivo, que a régua de tempo do painel é a mesma em todas as telas — e é também o que dá a próxima pergunta deste par: o que acontece entre a API do anunciante e a linha gravada nessa tabela.

Perguntas frequentes

As respostas curtas, para quem chegou pela pergunta.

Star schema não é coisa de data warehouse antigo?
O modelo é dos anos 1990 e continua valendo porque o problema que ele resolve não mudou: separar o que se mede do que descreve a medida, para que uma pergunta nova não exija uma tabela nova. O que mudou foi o porte — hoje ele cabe num banco de borda com dezenas de milhares de linhas por dia, sem cluster e sem time dedicado.
Qual a diferença entre star schema e uma tabela única com tudo dentro?
A tabela única responde bem à pergunta para a qual foi montada e mal a todas as outras. No star schema, a pergunta muda e o dado não: cortar por outra dimensão é um GROUP BY, não um arquivo novo. Em compensação, ele exige declarar o grão e a aditividade de cada medida antes de começar.
Como escolher o grão de uma tabela de fatos?
Guarde sempre no grão mais fino que a fonte entrega, mesmo sem pergunta atual que precise desse detalhe. Agregar para cima é um GROUP BY; descer é impossível, porque o detalhe que não foi gravado não existe. É a única decisão do projeto sem volta barata.
Por que a receita aparece dobrada quando somo a coluna de total do pedido?
Porque numa tabela no grão de item o valor total do pedido se repete em cada linha do mesmo pedido. Somar essa coluna multiplica a receita pelo número médio de itens por pedido. Para receita de pedido, colapse para o grão de pedido antes de somar; para receita de item, some a coluna que vive no grão da linha.
Preciso de arquitetura medalhão (bronze, prata e ouro)?
Só quando o porte pedir: volume que não cabe numa máquina, mais de um time escrevendo na mesma base, ou custo de reprocessar do zero maior que o de manter cópias. Abaixo disso, materializar três camadas adiciona latência e superfície de erro. A ideia de camadas se aproveita; a física, não.

Bibliografia

De onde vem o que não inventamos.

  • Ralph Kimball e Margy Ross, The Data Warehouse Toolkit, 3ª edição os quatro passos do projeto dimensional, grão, aditividade, dimensão conformada, bus matrix e o capítulo dedicado à dimensão de data.
  • Bill Inmon, Building the Data Warehouse o contraponto top-down ao modelo dimensional — útil para entender o que se está escolhendo, e não só o que se está adotando.
  • Documentação da Databricks sobre medallion architecture a definição de bronze, prata e ouro usada no bloco de porte.
  • Jordan Tigani, "Big Data is Dead" (MotherDuck, 2023) o argumento de que a maioria dos problemas de dados não tem o tamanho que a arquitetura escolhida pressupõe.