13 Antipadrões de Banco de Dados que Degradam Performance
Consultas lentas, locks e uso excessivo de CPU muitas vezes vêm de antipadrões de banco de dados. Neste guia, listamos 13 erros comuns e como evitá-los, com critérios práticos para cada situação.
Consultas lentas, locks e uso excessivo de CPU muitas vezes vêm de antipadrões de banco de dados. Neste guia, listamos 13 erros comuns e como evitá-los, com critérios práticos para cada situação.
Consultas lentas, locks inesperados e uso excessivo de CPU raramente aparecem por acaso. Na maioria dos casos, eles vêm de antipadrões de banco de dados: práticas comuns que parecem inofensivas no início, mas que degradam a performance conforme os dados crescem. Neste guia, listamos 13 deles, do mais crítico ao mais sutil, com critérios concretos para identificar e corrigir cada um.
1. Falta de índices em colunas usadas em WHERE e JOIN
Sem índice, o banco faz uma varredura completa (full scan) em cada consulta. Se a tabela tem 1 milhão de linhas, cada busca lê todas elas. Crie índices para as colunas que aparecem em filtros e junções, mas avalie o custo de escrita: cada índice extra torna INSERT e UPDATE mais lentos.
2. Uso excessivo de SELECT *
Buscar todas as colunas quando você precisa de duas aumenta o tráfego de rede e o uso de memória. Além disso, impede o uso de índices de cobertura. Liste apenas as colunas necessárias. Em uma tabela com 50 colunas, isso pode reduzir o tempo de resposta em até 70%.
3. Problema N+1 em consultas ORM
Um loop que executa uma consulta para cada registro é o clássico N+1. Se você tem 100 pedidos e busca o cliente de cada um, são 101 consultas. Use JOIN ou eager loading para reduzir a 1 ou 2 consultas. Ferramentas como o Django Debug Toolbar ou o Hibernate Statistics ajudam a detectar.
4. Chaves primárias naturais longas
Usar strings longas ou múltiplas colunas como chave primária infla os índices e torna as junções mais lentas. Prefira chaves sintéticas (inteiros ou UUID) e mantenha a chave natural como única. Um índice com chave de 50 bytes é 5 vezes maior que um de 10 bytes.
5. Normalização excessiva
Dividir demais as tabelas gera JOINs desnecessários. Uma consulta que poderia ler uma tabela passa a combinar 5. A normalização até a 3ª forma normal é recomendada, mas avalie a desnormalização controlada para relatórios e leituras frequentes. Um exemplo: armazenar o total de um pedido em vez de calcular por soma a cada acesso.
6. Falta de paginação em consultas pesadas
Retornar 10 mil registros de uma vez trava a aplicação e o banco. Use LIMIT e OFFSET, ou melhor, paginação por cursor (WHERE id > último_id). Em tabelas grandes, OFFSET alto é lento porque o banco descarta linhas após lê-las.
7. Locks de longa duração
Transações que ficam abertas por minutos seguram locks e bloqueiam outras operações. Mantenha transações curtas e evite lógica de negócio dentro delas. Se uma transação precisa de 5 segundos, o banco pode ficar inacessível para escrita nesse período.
8. Consultas com funções em colunas indexadas
WHERE YEAR(data) = 2024 impede o uso do índice em data. O banco precisa calcular a função em cada linha. Reescreva como WHERE data >= '2024-01-01' AND data < '2025-01-01'. Isso permite busca por índice e reduz o tempo de resposta em ordens de magnitude.
9. Uso de curingas no início de padrões LIKE
LIKE '%texto' não usa índice, mesmo que a coluna seja indexada. Para buscas por prefixo (LIKE 'texto%'), o índice funciona. Se você precisa buscar no meio da string, considere full-text search ou trigramas (como pg_trgm no PostgreSQL).
10. Excessivas colunas em uma tabela
Tabelas com mais de 100 colunas costumam misturar entidades diferentes. Isso aumenta o tamanho de cada linha, reduz o número de linhas por página e degrada a varredura. Separe em tabelas relacionadas, mas sem cair no antipadrão 5.
11. Falta de monitoramento de planos de execução
Sem analisar o EXPLAIN, você age no escuro. Um plano de execução mostra se o banco usa índice, faz full scan ou ordena em disco. Incorpore a análise de planos ao revisar cada consulta nova. Ferramentas como pgAdmin e MySQL Workbench exibem isso visualmente.
12. Testes de performance com dados de produção ausentes
Testar com 100 linhas não revela problemas que aparecem com 1 milhão. Use uma amostra representativa dos dados reais, incluindo distribuição de valores. Um índice pode funcionar em teste e falhar em produção se os dados forem muito diferentes.
13. Ignorar a manutenção de índices e estatísticas
Com o tempo, índices ficam fragmentados e estatísticas desatualizadas. O otimizador toma decisões ruins. Agende rotinas de VACUUM (PostgreSQL), UPDATE STATISTICS (SQL Server) ou OPTIMIZE TABLE (MySQL). Em tabelas com muitas escritas, a frequência semanal é comum.
A ordem importa: comece pelos itens 1 a 3, que têm maior impacto na maioria dos sistemas. Para bancos com volume alto, os itens 6 a 8 evitam gargalos progressivos. Avalie cada antipadrão no contexto do seu schema e dos seus padrões de acesso. Se você não sabe por onde começar, rode o EXPLAIN nas suas 10 consultas mais lentas e compare com esta lista.
FAQ
O que é um antipadrão de banco de dados?
É uma prática comum que parece eficiente, mas que prejudica a performance ou a manutenibilidade a longo prazo. Exemplos incluem falta de índices, SELECT * e N+1 queries. Identificá-los exige análise de planos de execução e entendimento do volume de dados.
Como saber se minha consulta está lenta por causa de antipadrão?
Use o EXPLAIN ou equivalente para ver se a consulta faz full scan, usa índices e quantas linhas lê. Se o número de linhas lidas é muito maior que o retornado, há um antipadrão. Compare o tempo de resposta com o esperado para o volume.
Qual o antipadrão mais comum em aplicações web?
O problema N+1 em ORMs é frequente, especialmente em frameworks como Django e Hibernate. Ele gera centenas de consultas pequenas onde uma única com JOIN resolveria. Ferramentas de debug mostram a quantidade de queries por página.
Posso desnormalizar tabelas para melhorar performance?
Sim, em casos específicos. Desnormalização controlada, como armazenar totais calculados, reduz JOINs e acelera leituras. Mas mantenha consistência com triggers ou jobs. Avalie o trade-off entre performance de leitura e complexidade de escrita.
Como evitar antipadrões em um projeto novo?
Defina padrões de modelagem no início, como chaves sintéticas, índices para colunas de filtro e proibição de SELECT *. Revise planos de execução antes de subir cada migração. Teste com volume de dados realista desde o início.
Qual a diferença entre antipadrão e má prática?
Antipadrão é uma solução que parece correta em um contexto, mas que gera problemas em outro, como usar uma chave natural longa. Má prática é um erro claro, como não usar transações. Antipadrões exigem análise de trade-offs; má prática, correção direta.
Camila Bressane Drumond
Editora de Cibersegurança
Traduz ameaça digital para gente comum, sem alarmismo e sem subestimar.
Ver todos os artigos →