Skip to content

06 — Inventário de tabelas escaláveis

Ref: 00_INDEX · Insumo para F1, F2, F5

Contexto

Listar as tabelas que crescem proporcional ao volume da escola e marcar onde hoje elas são lidas via fetchAllRows em rota UI (anti-padrão) ou via paginação real.

Projeção (escola "grande" alvo: 5k alunos, 1 ano letivo)

TabelaCardinalidade esperadaCrescimento porLida via fetchAllRows em UI?Risco
alunos5k–10kmatrícula❌ paginação🟢
inscricoes_olimpiada5k × N olimpíadas × N anos = 30k–100kolimpíada × aluno × ano8 lugares em resultados-queries.ts🔴
resultados_alunoigual a inscrições × fases (~50k–200k)fase × inscrição⚠️ via queryInChunks (OK)🟡
mensagens_enviadas5k × 10 campanhas/ano = 50k+campanha × destinatário? (não auditado)🟡
logs_transacoesalto (toda CUD)operação?🟡
aluno_responsaveis~5k–10kaluno × responsaveln/a🟢
aluno_turma_historico5k × N anos = 25k+matrícula × anon/a🟡
controle_aplicacoes~1k–5kaplicaçãojá paginado (V3)🟢
notificacoesmédioevento × usuário?🟡
portal_login_tentativasalto (rate-limit)tentativasó agregado em SQL🟢
mural_dados_publicadosmédio (snapshot)publicaçãopaginado via snapshot🟢
email_outboxaltoenviosó drenado por cron (OK)🟢

Tabelas a confirmar (sub-tarefa da Onda C)

Para cada 🟡/🔴 marcado com "?":

  1. grep por todas as queries que tocam a tabela em supabase/functions/.
  2. Classificar leitura UI vs job vs agregação.
  3. Sugerir SQL agregado / range / fila conforme o caso.

Índices a validar (Onda A)

Confirmar via EXPLAIN ANALYZE antes do fix:

  • inscricoes_olimpiada (escola_id, olimpiada_id, ano_edicao) — composto, usado em todas as queries hot.
  • inscricoes_olimpiada (escola_id, olimpiada_id, nivel_id) — filtro de nível.
  • resultados_aluno (inscricao_id, fase_id) — já é a chave de conflict; deve haver UNIQUE INDEX.
  • mensagens_enviadas (escola_id, criado_em DESC) — para listagem cronológica paginada.

Próximas etapas

→ As frentes F1/F2 são suficientes para mover inscricoes_olimpiada de 🔴 para 🟢. → Sub-auditoria de mensagens_enviadas, logs_transacoes, notificacoes na Onda C.