Problema
ORM gerando dezenas de queries por request, índice “que resolve tudo” que na verdade não cobre ordenação, e produção lenta sem saber qual query drena o pool.
Solução
Definir budget de queries por endpoint (ex.: checkout < 10 queries). Usar EXPLAIN (ANALYZE, BUFFERS) em staging com volume realista. Logar queries acima de threshold com query fingerprint, nunca com PII em texto livre.
Arquitetura
ORM → DataLoader / joins explícitos onde necessário
→ índices alinhados a WHERE + ORDER BY
→ pg_stat_statements / APM com span de DB
- Separar leituras analíticas pesadas para réplica ou warehouse.
Código
// ruim: loop com await
for (const id of orderIds) {
items.push(await db.item.findMany({ where: { orderId: id } }));
}
// melhor: uma consulta + agrupamento em memória
const allItems = await db.item.findMany({
where: { orderId: { in: orderIds } },
});
const byOrder = groupBy(allItems, (i) => i.orderId);Performance
Índice parcial para subconjuntos quentes; LIMIT + cursor; vacuum/autoanalyze saudáveis.
Melhorias futuras
Planos estáveis (pg_hint_plan com cautela); particionamento por tempo; cache de leitura com invalidação clara.
Conclusão
Otimizar SQL é ciência de medição + disciplina de ORM. Demonstrar isso reforça perfil backend sólido.