Escrever SQL não é difícil; difícil é escrever SQL bem.
Beekeeper Studio é um cliente de banco de dados gratuito e open source
A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit
O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.
Consultas que funcionam bem em desenvolvimento começam a ficar lentas em produção. A falta de um ORDER BY retorna resultados inconsistentes, um SELECT * rápido quebra quando o schema muda, e filtros que parecem inofensivos em um dataset pequeno podem travar tudo em escala.
Com o tempo, você começa a perceber padrões que se sustentam e padrões que não.
Então aqui estão sete boas práticas de SQL, trazidas pela equipe por trás do Beekeeper Studio, a GUI de banco de dados moderna, open source e multiplataforma.
🔖 Referência rápida: Enquanto aprende essas boas práticas, mantenha nossa Cheat Sheet da linguagem SQL à mão para consultas rápidas sobre SELECT, WHERE, JOINs, agregações e outros comandos SQL essenciais.
1. Seja específico — evite SELECT *
Buscar todas as colunas com SELECT * pode parecer rápido e flexível. Você não precisa decidir quais colunas retornar e quais excluir, e funciona bem enquanto você ainda está explorando um dataset.
Essa flexibilidade tem um custo. À medida que os schemas evoluem ou os joins se multiplicam, SELECT * pode trazer colunas duplicadas ou inesperadas, deixar suas consultas lentas e dificultar a depuração.
Escolher colunas específicas deixa a intenção clara e protege seu código de quebras silenciosas.
-- Risky
SELECT * FROM user_profiles WHERE user_id = 42;
-- Better
SELECT user_id, display_name, avatar_url
FROM user_profiles
WHERE user_id = 42;
2. Use CTEs para simplificar lógicas complexas
Subconsultas aninhadas funcionam, mas rapidamente ficam ilegíveis. É difícil ver o que está sendo filtrado onde, e depurar geralmente significa rolar para frente e para trás entre camadas de parênteses.
Common Table Expressions (cláusulas WITH) permitem dividir uma consulta em etapas nomeadas. Cada etapa pode ser executada e testada isoladamente, deixando a intenção mais clara e os erros mais fáceis de rastrear. Só lembre que alguns bancos materializam CTEs, então subconsultas inline podem ser mais rápidas em loops apertados.
-- Hard to follow
SELECT customer_id, COUNT(*)
FROM (
SELECT customer_id, created_at
FROM orders
WHERE created_at > now() - interval '7 days'
) o
GROUP BY customer_id;
-- Clearer
WITH recent_orders AS (
SELECT customer_id, created_at
FROM orders
WHERE created_at > now() - interval '7 days'
)
SELECT customer_id, COUNT(*)
FROM recent_orders
GROUP BY customer_id;
3. Comente a intenção, não a sintaxe
Comentários inline que repetem o que o SQL já mostra não agregam muito. O contexto que você vai esquecer depois não é o que a consulta faz, mas por que ela existe.
Uma nota curta sobre o propósito ou uso facilita revisitar ou passar o código adiante. Escreva para o seu eu do futuro ou para o próximo desenvolvedor que tentar entender por que essa consulta importa.
-- Find users who signed up but never activated
-- Used in the weekly retention cohort report
SELECT u.id, u.email
FROM users u
LEFT JOIN events e
ON u.id = e.user_id
AND e.name = 'account_activated'
WHERE e.id IS NULL
AND u.created_at > now() - interval '7 days';
4. Faça filtros que aproveitem os índices
Índices só ajudam quando seus filtros são sargable (abreviação de Search ARGument ABLE). Na prática, isso significa que o banco pode usar o índice diretamente em vez de varrer todas as linhas.
Se você envolve uma coluna em uma função — por exemplo LOWER(email) ou DATE(created_at) — o otimizador não consegue usar o índice. Até conversões de tipo podem ter o mesmo efeito. A consulta continua funcionando, mas fica mais lenta à medida que seus dados crescem.
-- Not sargable: disables index
WHERE LOWER(email) = 'test@example.com';
-- Sargable: uses existing index
WHERE email = 'test@example.com';
Para manter os filtros eficientes, escreva-os de acordo com a forma como os dados são armazenados. Se precisar de comparação sem diferenciar maiúsculas e minúsculas, armazene os valores em um formato consistente ou adicione um índice funcional. Para datas, filtre por intervalo em vez de transformar a coluna — fica mais claro e mantém o índice em uso.
-- Not sargable
WHERE DATE(created_at) = '2025-08-04';
-- Sargable
WHERE created_at >= '2025-08-04'
AND created_at < '2025-08-05';
5. Filtre antes de fazer o join
É tentador fazer join de tudo primeiro e filtrar depois, principalmente ao explorar ou prototipar. Mas cada join multiplica as linhas, e cada linha desnecessária deixa sua consulta mais lenta e mais difícil de o otimizador planejar.
Em vez disso, reduza cada tabela antes de combiná-las. Assim, o banco só faz join dos dados que realmente importam — reduzindo o uso de memória, melhorando a eficiência do cache e mantendo o plano de execução previsível.
-- Joins every user, even inactive ones
SELECT e.*
FROM users u
JOIN events e ON e.user_id = u.id;
-- Filter first: only active, recently seen users
WITH active_users AS (
SELECT id
FROM users
WHERE active = true
AND last_seen > now() - interval '90 days'
)
SELECT e.*
FROM active_users u
JOIN events e ON e.user_id = u.id;
6. Prefira EXISTS a IN para verificar relacionamentos
Quando você verifica se existem linhas relacionadas, IN resolve — até deixar de resolver. Ele monta uma lista completa de valores, compara cada um e trata NULLs de um jeito que pode esconder correspondências válidas.
EXISTS funciona de outra forma. Ele retorna true assim que encontra uma correspondência e não é afetado por NULLs na subconsulta. O resultado é mais rápido e mais confiável, especialmente em datasets grandes.
-- Works, but can be slower and NULL-prone
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM orders);
-- Clear and efficient: stops at first match
SELECT *
FROM users u
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);
7. Sempre especifique ORDER BY
O SQL não garante a ordem das linhas a menos que você peça.
Sem um ORDER BY, o banco é livre para retornar as linhas na sequência que for mais conveniente, e isso pode mudar entre execuções, ambientes ou até pequenas atualizações.
Pode parecer estável em desenvolvimento, mas assim que índices, planos de execução ou o volume de dados mudarem, você vai começar a ver paginação imprevisível ou resultados de API inconsistentes.
-- Looks fine until it isn't
SELECT id, name
FROM users
WHERE active = true
LIMIT 10;
-- Predictable and reproducible
SELECT id, name
FROM users
WHERE active = true
ORDER BY created_at DESC
LIMIT 10;
Juntando tudo
As melhores consultas são aquelas que você entende um ano depois. Elas têm intenção clara, comportamento previsível e nenhuma surpresa escondida.
Esse é o espírito por trás desses hábitos. São práticas que usamos todos os dias no Beekeeper Studio para manter as consultas legíveis, consistentes e rápidas em todos os bancos com que trabalhamos.
Você pode baixar uma versão em PDF gratuita deste guia para ter à mão ou compartilhar com sua equipe:
Baixe 7 hábitos de SQL para desenvolvedores ocupados
Com o Beekeeper Studio você coloca esses hábitos em prática no dia a dia, usando um editor SQL moderno, multiplataforma e open source feito para manter você no fluxo.
- Mais de 20 bancos de dados suportados: Postgres, MySQL, SQLite, SQL Server, MongoDB, Redis e muito mais.
- Editor rápido e responsivo: autocomplete que conhece o schema, consultas em abas e destaque de sintaxe.
- Ferramentas visuais de dados: navegue por tabelas, edite linhas e inspecione JSON sem perder o contexto.
- Assistente de IA (privacidade em primeiro lugar): a ferramenta de IA para código que faltava no seu banco de dados — conhece o schema, funciona com o LLM de sua escolha e ajuda você a explorar e refinar consultas mais rápido.