Cover do episódio 62: Por que SQL ainda importa quando você trabalha com APIs
#06218 de fevereiro, 20193 min leituraTecnologia sem HypeS3 · 2018–2019

Por que SQL ainda importa quando você trabalha com APIs

Em 2019 achei que podia ignorar SQL e só usar ORM. Errei. Aqui está o momento em que entendi que SQL não é detalhe de implementação — é a língua dos dados.

SQLBanco de DadosBackendPerformance

Passei os primeiros meses usando ORM sem entender o SQL que gerava.

Chamava User.find({ where: { status: 'ativo' } }) e recebia os dados. Funcionava. Não me importei muito com o que acontecia embaixo.

Até a query levar 8 segundos para retornar.


O sistema tinha uma funcionalidade de relatório: listava todos os leads do mês, com dados da empresa e do vendedor responsável.

Funcionava perfeitamente com 200 registros no banco de testes.

Em produção, com 15.000 registros, demorava 8 segundos. O cliente reclamou. Fui investigar.

Abri o log do banco e vi o SQL que o ORM estava gerando:

SELECT * FROM leads WHERE mes = '2019-02'
SELECT * FROM empresas WHERE id = 1
SELECT * FROM empresas WHERE id = 1
SELECT * FROM empresas WHERE id = 14
SELECT * FROM empresas WHERE id = 14
-- ... repetido 15.000 vezes
SELECT * FROM vendedores WHERE id = 3
SELECT * FROM vendedores WHERE id = 3
-- ... repetido 15.000 vezes

Era o problema N+1. Para cada lead, o ORM fazia uma query separada para buscar a empresa e o vendedor. 15.000 leads = 30.001 queries.

O ORM escondia isso. Parecia uma operação simples. Era 30.000 round-trips para o banco.


Aprendi a escrever o JOIN manualmente:

SELECT
  leads.id,
  leads.nome,
  leads.email,
  empresas.nome as empresa_nome,
  vendedores.nome as vendedor_nome
FROM leads
JOIN empresas ON leads.empresa_id = empresas.id
JOIN vendedores ON leads.vendedor_id = vendedores.id
WHERE leads.mes = '2019-02'

Uma query. 15.000 resultados. 0.3 segundos.

Aprendi duas coisas nesse dia: o que é JOIN de verdade, e que ORM é abstração — abstração tem custo, e o custo fica escondido até não ficar mais.


ORM é útil. Não estou dizendo para jogar fora.

Mas você precisa entender o SQL que ele gera porque quando fica lento, o problema geralmente está na query — e se você não consegue ler SQL, não consegue diagnosticar. O dado que aparece errado na tela muitas vezes é JOIN mal feito ou WHERE incorreto. Algumas queries são impossíveis de expressar via ORM. Se você não sabe SQL, você fica preso nas limitações da abstração.

O mínimo prático: SELECT com WHERE/ORDER BY/LIMIT. JOIN (INNER retorna só match dos dois lados; LEFT retorna todos do lado esquerdo, match ou não). Índices — coluna que você usa em WHERE ou JOIN precisa de índice ou vai fazer full scan em tabela grande. COUNT/SUM/GROUP BY para cálculos sobre conjuntos. E EXPLAIN ANALYZE <query> — quando algo está lento, esse é o primeiro passo.

-- Quais empresas têm mais leads?
SELECT empresa_id, COUNT(*) as total
FROM leads
GROUP BY empresa_id
ORDER BY total DESC
LIMIT 10;

Não precisa de tutorial. Precisa de banco com dados reais e curiosidade para perguntar coisas sobre eles.

Essa semana: pega a query mais lenta do seu sistema e abre o log do banco para ver o SQL real que está sendo executado. Vai encontrar pelo menos uma surpresa.