Pular para o conteúdo

1-N, N-1, N-N e anti-fan-out

Aula 4 de 108 minOperarAtualizada em 2026-10-04

Vídeo em produção

A gravação desta aula está no lote de produção. O objetivo, o exercício e a documentação já valem. Duração-alvo: 8 min.

Objetivo: Prever quando a soma duplica

Selo de estado: Preview (teto atual do produto) · Curso ACD-310 — Modelo semântico e modelagem dimensional · Aula 4 de 10 · Atualizado em 2026-10-04.

Objetivo#

Ao final desta aula você vai prever, antes de rodar a consulta, quando um join vai duplicar linhas e inflar uma soma — e entender por que o produto recusa a agregação nesses casos.

Vídeo#

Identificador no manifesto: acd-310-04-relacoes-cardinalidade-fan-out · duração-alvo 8 min · tela do produto: /dashboards.

Roteiro:

  1. 00:00–01:20 — As três cardinalidades: 1-N/N-1, 1-1, N-N · tela: /dashboards/[id] (diagrama do modelo, relação vendas→produtos)
  2. 01:20–03:00 — Por que a cardinalidade não é decorativa: o join físico sempre vai fato → dimensão · tela: /dashboards/[id] (propriedades da relação)
  3. 03:00–05:30 — Fan-out na prática: somar filiais.meta sobre o join com vendas e ver o bloqueio · tela: /dashboards/[id] (visual novo, mensagem de recusa)
  4. 05:30–07:00 — Lendo a mensagem didática e corrigindo: mover a medida para o fato certo · tela: /dashboards/[id] (medida corrigida, visual voltando a funcionar)
  5. 07:00–08:00 — N-N sem ponte: por que é tratado como ambíguo e recusado · tela: /dashboards/[id] (tentativa de ligar produtos↔promocoes direto)

Conteúdo#

As aulas 2 e 3 trataram cardinalidade e direção como um detalhe técnico do diagrama. Esta aula mostra por que ela tem efeito real sobre o número final — e por que, às vezes, o ingestia.bi se recusa a somar algo em vez de arriscar um total errado. A referência completa é Relacionamentos, cardinalidade e direção de filtro.

As três cardinalidades

CardinalidadeSignificadoExemplo Aurora
1-N / N-1Um do lado dimensão, muitos do lado fato — o caso normal.Um produto tem muitas linhas em vendas.
1-1Uma linha de cada lado.filiais ↔ uma tabela de metadados por filial (quando existir).
N-NMuitos dos dois lados — exige tabela-ponte (aula 5).produtos ↔ promocoes, via produto_promocao.

A cardinalidade não é decorativa: ela é o que o gerador de SQL usa para decidir se uma soma é segura.

Por que a soma às vezes é recusada: fan-out

Quando um join 1-N multiplica linhas, uma soma sobre o lado "um" seria contada mais de uma vez. O exemplo clássico, direto do Aurora: filiais tem uma coluna meta. Se você juntar filiais a vendas (uma filial, muitas vendas) e tentar SOMA(meta) sobre esse join, a meta da filial é contada uma vez por venda daquela filial — um número várias vezes maior que o real.

O ingestia.bi detecta esse estouro de linhas (as funções internas são hopFansOut/joinDuplicatesRows) e bloqueia a agregação afetada, com uma mensagem didática, em vez de entregar o total errado em silêncio. É a mesma situação que o Power BI resolve pedindo para você modelar corretamente antes; aqui é uma guarda automática, consciente do grão que você definiu na aula 2.

Aviso

Se uma soma aparecer bloqueada no editor, o problema é quase sempre de grão: você está somando uma medida do lado "um" através de um join que a duplica. A correção normal é colocar a medida no fato de grão correto, ou somar do lado certo da relação — nunca forçar o número a aparecer ignorando o aviso.

Com dados sintéticos: se filiais tem 2 linhas e vendas tem 6 linhas ligadas a elas por cidade, somar filiais.meta direto sobre esse join contaria a meta de cada filial 3 vezes (uma por venda) — exatamente o caso que a proteção bloqueia.

Direção de filtro (prévia da aula 5)

Além da cardinalidade, cada relação tem uma direção de filtro. Por padrão, o filtro flui do lado "um" para o lado "muitos" — escolher uma categoria em produtos recorta as vendas daquela categoria, nunca o contrário. A aula 5 detalha o modo bidirecional opt-in (crossFilter: "both"), que liga a propagação nos dois sentidos quando você realmente precisa.

N-N sem ponte: por que é recusado

Uma relação muitos-para-muitos — por exemplo, produtos ↔ promocoes, onde um produto pode estar em várias promoções e uma promoção pode ter vários produtos — não pode ser ligada como se fosse N-1. Sem uma tabela-ponte explícita (como produto_promocao), o significado da relação fica indefinido, e o modelo trata isso como ambíguo e recusa a ligação — em vez de gerar um SQL que pareceria funcionar, mas contaria errado. A solução com tabela-ponte é o tema da aula 5.

Como isso aparece no produto

No editor do dashboard (/dashboards/[id]), cada relação do diagrama tem uma propriedade de cardinalidade (1-1 | 1-N | N-1 | N-N) e de direção de filtro. O gerador de SQL encontra o caminho de join percorrendo esse grafo e emite sempre LEFT JOIN no sentido fato → dimensão. Quando uma agregação cruzaria um caminho que duplica linhas, o editor mostra a recusa no próprio visual, com uma explicação em português — não um erro técnico de banco de dados.

Erros comuns

  • Ignorar o aviso e tentar "forçar" o número. Reescrever a fórmula para contornar o bloqueio sem entender a causa quase sempre reintroduz a duplicação de outro jeito.
  • Confundir o bloqueio com um bug. Ele é uma proteção — o produto prefere avisar a entregar um total errado em silêncio.
  • Tentar ligar N-N "na mão" como N-1. Isso não contorna a recusa: o modelo detecta a ambiguidade e recusa de qualquer forma, porque o problema é estrutural, não de sintaxe.

Nota

A detecção de fan-out e a resolução do caminho de join são GA-candidato — cobertas por um conjunto de testes de referência, com resultado idêntico a cada execução. O desempenho desse mesmo join em BigQuery de produção real continua Preview (NÃO MEDIDO sem credencial de nuvem).

Faça você mesmo#

No workspace de treino Aurora Varejo (abra /dashboards no console, editor de um painel, aba do modelo):

  1. Confirme que filiais está ligada a vendas por filial_id, cardinalidade N-1.
  2. Crie um visual novo e tente somar filiais.meta (ou outra coluna numérica de uma dimensão) diretamente sobre esse join.
  3. Observe a mensagem de recusa — anote exatamente o que ela diz.
  4. Em vez disso, crie a medida correta no fato: SOMA(valor) sobre vendas, agrupada por filiais.regiao.
  5. Compare: a medida do fato funciona normalmente; a tentativa de somar a dimensão continua bloqueada.
  6. (Opcional) Tente ligar produtos diretamente a uma tabela hipotética promocoes sem tabela-ponte e observe a recusa por ambiguidade.

Você terminou quando conseguir reproduzir o bloqueio de fan-out de propósito, explicar por que ele acontece e corrigi-lo movendo a soma para o fato certo.

Checagem rápida#

Três perguntas no final da aula, corrigidas no servidor. A aula só conta como concluída depois da checagem.

Documentação relacionada#

Capacidades ensinadas#

C05.1 · C05.4 — o selo exibido na aula é sempre o estado mais conservador entre as capacidades citadas; nada aqui é "GA".

Carregando seu progresso…