Consultas SQL eficientes: como escrever SQL mais rápido e leve
Lição 10.2 · Tempo de leitura: ~10 min · Tarefas para praticar ↓
Esta lição apresenta fundamentos para escrever consultas SQL de alto desempenho. Você vai aprender como evitar carga desnecessária no banco, por que SELECT * costuma prejudicar performance e como filtrar dados de forma eficiente. Também veremos técnicas práticas para acelerar consultas em grandes volumes. Ao final, você conseguirá escrever SQL eficiente e responsável com recursos do servidor.
Na lição anterior, focamos em legibilidade para pessoas. Mas o SQL também precisa ser eficiente para o mecanismo do banco. Até uma consulta bem formatada pode ser lenta se obrigar o servidor a executar trabalho desnecessário.
A eficiência de consulta afeta diretamente a velocidade de aplicações e relatórios. Em cenários de alto volume, a diferença entre "funciona" e "otimizado" pode ser enorme.
SGBDs modernos possuem otimizadores potentes, mas eles não conhecem toda a lógica de negócio e não corrigem tudo automaticamente. Qualidade de SQL continua sendo responsabilidade do desenvolvedor.
Regra de ouro: busque apenas o necessário
Uma causa comum de lentidão é transferir dados demais entre servidor e cliente.
Evite SELECT *
SELECT * é útil em exploração inicial, mas deve ser evitado no SQL final.
- Tráfego extra: você retorna colunas que não precisa.
- Menos chance de plano com índice cobrindo colunas: pedir tudo dificulta planos mais eficientes.
- Código frágil: novas colunas podem alterar performance e comportamento.
-- Ruim
SELECT * FROM film;
-- Melhor
SELECT film_id, title, release_year
FROM film;
Otimização de filtragem
A forma de limitar linhas determina quanto trabalho o SGBD vai fazer.
Filtre no servidor o quanto antes
Aplique WHERE antes de operações pesadas. Quanto menos linhas seguirem para JOIN e GROUP BY, melhor.
Evite funções em WHERE (consultas SARGable)
Para aproveitar índices, predicados devem ser SARGable. Se você envolve uma coluna indexada em função, o otimizador pode deixar de usar o índice de forma eficiente.
-- Lento (Non-SARGable)
SELECT count(*)
FROM rental
WHERE YEAR(rental_date) = 2005;
-- Rápido (SARGable)
SELECT count(*)
FROM rental
WHERE rental_date >= '2005-01-01' AND rental_date < '2006-01-01';
Trabalhando com JOIN
Junções estão entre as operações mais custosas em SQL.
- Filtre antes de juntar sempre que possível.
- Verifique índices nas chaves de relação.
- Evite
CROSS JOINsem necessidade real. - Use
EXISTSpara testes de existência.
-- Menos eficiente
SELECT DISTINCT c.first_name, c.last_name
FROM customer c
JOIN payment p ON c.customer_id = p.customer_id;
-- Mais eficiente para existência
SELECT c.first_name, c.last_name
FROM customer c
WHERE EXISTS (
SELECT 1 FROM payment p WHERE p.customer_id = c.customer_id
);
Use LIMIT durante validação
Ao depurar, use LIMIT para evitar retorno acidental de milhões de linhas.
SELECT customer_id, first_name, last_name
FROM customer
WHERE active = 1
LIMIT 10;
Exemplo prático: otimizando um relatório
Suponha que precisamos encontrar filmes alugados mais de 30 vezes em uma categoria específica.
Abordagem menos eficiente:
SELECT f.title, COUNT(r.rental_id)
FROM film f
JOIN inventory i ON f.film_id = i.film_id
JOIN rental r ON i.inventory_id = r.inventory_id
JOIN film_category fc ON f.film_id = fc.film_id
JOIN category c ON fc.category_id = c.category_id
WHERE c.name = 'Action'
GROUP BY f.title
HAVING COUNT(r.rental_id) > 30;
Abordagem mais eficiente:
Se soubermos o ID da categoria, podemos evitar um JOIN adicional.
SELECT f.title, COUNT(r.rental_id) AS rental_count
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
JOIN inventory i ON f.film_id = i.film_id
JOIN rental r ON i.inventory_id = r.inventory_id
WHERE fc.category_id = 1 -- Usa ID em vez de busca textual
GROUP BY f.film_id, f.title
HAVING COUNT(r.rental_id) > 30;
Observação: filtrar por ID numérico costuma ser mais rápido do que filtrar por nome textual e pode reduzir joins desnecessários.
Principais conclusões desta lição:
- Evite
SELECT *em consultas de produção. - Filtre cedo com
WHERE. - Escreva condições SARGable para permitir uso de índices.
- Use
EXISTSpara verificação de existência. - Use
LIMITna exploração e depuração. - Prefira filtros por chaves numéricas.
Perguntas frequentes
Por que SELECT * é ruim em produção?
Ele retorna colunas desnecessárias, aumenta tráfego e pode piorar planos de execução. Listar colunas explicitamente é mais seguro.
O que significa SARGable na prática?
Significa permitir busca eficiente por índice. Funções em colunas indexadas costumam atrapalhar isso.
Quando usar EXISTS em vez de JOIN?
Quando você só precisa saber se existe linha relacionada e não precisa retornar colunas da tabela secundária.
Perguntas de entrevista
Quais primeiros passos você toma ao encontrar consulta SQL lenta?
Verifico SELECT *, seletividade de WHERE e predicados não SARGable. Depois avalio a estratégia de join e volume de linhas processadas.
Por que filtrar cedo melhora desempenho?
Porque reduz linhas envolvidas em joins, ordenações e agregações, diminuindo o custo total do plano.
Diferença de performance entre JOIN e EXISTS?
JOIN combina conjuntos de linhas e é necessário quando você precisa de colunas de ambas as tabelas. EXISTS costuma ser melhor para verificações sim/não.