Licao 10.2 · Tempo de leitura: ~10 min
Esta licao apresenta fundamentos para escrever consultas SQL de alto desempenho. Voce vai aprender como evitar carga desnecessaria no banco, por que SELECT * costuma prejudicar performance e como filtrar dados de forma eficiente. Tambem veremos tecnicas praticas para acelerar consultas em grandes volumes. Ao final, voce conseguira escrever SQL eficiente e responsavel com recursos do servidor.
Na licao anterior, focamos em legibilidade para pessoas. Mas o SQL tambem precisa ser eficiente para o mecanismo do banco. Ate uma consulta bem formatada pode ser lenta se obrigar o servidor a executar trabalho desnecessario.
A eficiencia de consulta afeta diretamente a velocidade de aplicacoes e relatorios. Em cenarios de alto volume, a diferenca entre "funciona" e "otimizado" pode ser enorme.
SGBDs modernos possuem otimizadores potentes, mas eles nao conhecem toda a logica de negocio e nao corrigem tudo automaticamente. Qualidade de SQL continua sendo responsabilidade do desenvolvedor.
Uma causa comum de lentidao e transferir dados demais entre servidor e cliente.
SELECT *SELECT * e util em exploracao inicial, mas deve ser evitado no SQL final.
-- Ruim
SELECT * FROM film;
-- Melhor
SELECT film_id, title, release_year
FROM film;
A forma de limitar linhas determina quanto trabalho o SGBD vai fazer.
Aplique WHERE antes de operacoes pesadas. Quanto menos linhas seguirem para JOIN e GROUP BY, melhor.
WHERE (consultas SARGable)Para aproveitar indices, predicados devem ser SARGable. Se voce envolve uma coluna indexada em funcao, o otimizador pode deixar de usar o indice de forma eficiente.
-- Lento (Non-SARGable)
SELECT count(*)
FROM rental
WHERE YEAR(rental_date) = 2005;
-- Rapido (SARGable)
SELECT count(*)
FROM rental
WHERE rental_date >= '2005-01-01' AND rental_date < '2006-01-01';
JOINJuncoes estao entre as operacoes mais custosas em SQL.
CROSS JOIN sem necessidade real.EXISTS para testes de existencia.-- 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 existencia
SELECT c.first_name, c.last_name
FROM customer c
WHERE EXISTS (
SELECT 1 FROM payment p WHERE p.customer_id = c.customer_id
);
LIMIT durante validacaoAo depurar, use LIMIT para evitar retorno acidental de milhoes de linhas.
SELECT customer_id, first_name, last_name
FROM customer
WHERE active = 1
LIMIT 10;
Suponha que precisamos encontrar filmes alugados mais de 30 vezes em uma categoria especifica.
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;
Observacao: filtrar por ID numerico costuma ser mais rapido do que filtrar por nome textual e pode reduzir joins desnecessarios.
Principais conclusoes desta licao:
SELECT * em consultas de producao.WHERE.EXISTS para verificacao de existencia.LIMIT na exploracao e depuracao.SELECT * e ruim em producao?Ele retorna colunas desnecessarias, aumenta trafego e pode piorar planos de execucao. Listar colunas explicitamente e mais seguro.
Significa permitir busca eficiente por indice. Funcoes em colunas indexadas costumam atrapalhar isso.
EXISTS em vez de JOIN?Quando voce so precisa saber se existe linha relacionada e nao precisa retornar colunas da tabela secundária.
Verifico SELECT *, seletividade de WHERE e predicados nao SARGable. Depois avalio estrategia de join e volume de linhas processadas.
Porque reduz linhas envolvidas em joins, ordenacoes e agregacoes, diminuindo o custo total do plano.
JOIN e EXISTS?JOIN combina conjuntos de linhas e e necessario quando voce precisa de colunas de ambas as tabelas. EXISTS costuma ser melhor para verificacoes sim/nao.
Na proxima licao, vamos aprofundar a analise de execucao e ver como indices aceleram consultas no nivel fisico.
-> Licao 10.3: Entendendo metodos de otimizacao de consultas