MySQL lento? Como acelerar consultas com índices compostos
Descubra como a ordem correta das colunas em índices compostos no MySQL elimina full table scans e acelera tabelas massivas de forma drástica.
Resumo
- Consultas sem índices adequados forçam o MySQL a ler a tabela inteira do disco linha por linha.
- O índice composto funciona como uma lista telefônica ordenada pela primeira coluna e depois pela segunda.
- A ordem das colunas na criação do índice define diretamente quais filtros conseguem aproveitá-lo.
- Colunas de igualdade devem vir sempre antes de colunas usadas para intervalos ou ordenação.
- Monitorar planos de execução com o comando EXPLAIN evita adivinhações na tunagem de desempenho.
Por que suas consultas no MySQL estão ficando lentas?
Quando um sistema cresce, o banco de dados costuma ser o primeiro gargalo a aparecer. Em tabelas com milhões de registros, uma busca simples pode demorar segundos preciosos, travando a aplicação inteira. Na prática, isso significa que o MySQL está fazendo um full table scan, que é a varredura completa da tabela. O banco é forçado a abrir e ler cada linha do arquivo no disco rígido para encontrar o que você pediu, exatamente como ler um livro inteiro da primeira à última página apenas para achar uma frase solta.
Para evitar esse esforço desnecessário, usamos os índices. Um índice no banco de dados funciona como o índice remissivo no final de um livro acadêmico ou técnico: um mapeamento ordenado que aponta exatamente em qual página ou bloco de dados a informação está guardada. Em vez de percorrer milhões de linhas, o motor do MySQL pula direto para o endereço correto. Contudo, quando filtramos por mais de um campo ao mesmo tempo — como buscar pedidos de um cliente específico em uma data específica —, um índice em uma única coluna deixa de ser suficiente e o sistema perde eficiência.
A solução para esse cenário é a criação de índices compostos, também conhecidos como índices multi-coluna. Trata-se de uma estrutura única que combina duas ou mais colunas da mesma tabela. Assim como já discutimos ao analisar como otimizar índices no PostgreSQL, a lógica por trás da estruturação de dados em motores relacionais exige critério técnico rigoroso. No entanto, colocar várias colunas juntas sem entender a regra de ouro da ordenação pode tornar o seu esforço totalmente inútil, pois o MySQL tem regras estritas de como consome essas estruturas.
Como funciona a ordem das colunas em um índice composto?
A característica mais importante de um índice composto é a seletividade e a hierarquia posicional. O MySQL organiza fisicamente os dados desse índice seguindo rigorosamente a ordem em que você declarou as colunas na hora do comando CREATE INDEX. Se você criar um índice com a estrutura (cliente_id, data_pedido), o banco primeiro ordena todas as linhas pelo código do cliente e, apenas para linhas onde o código do cliente é exatamente igual, ele organiza secundariamente pela data do pedido.
Na prática, essa mecânica cria a famosa Regra do Prefixo Esquerdo. Isso significa que o MySQL consegue aproveitar esse índice composto se a sua consulta filtrar pelo cliente_id sozinho, ou pelo cliente_id combinado com a data_pedido. Por outro lado, se a sua consulta tentar buscar apenas pela data_pedido ignorando o cliente_id, o índice se torna completamente inútil para aquele filtro. O banco não consegue pular para o meio da árvore de dados sem saber por qual cliente começar, invalidando todo o ganho de performance.
Essa lógica é idêntica ao funcionamento de uma lista telefônica impressa tradicional. Se as pessoas estão ordenadas primeiro pelo Sobrenome e depois pelo Nome, você acha facilmente alguém sabendo o sobrenome. Se você procurar apenas pelo nome 'João' sem saber o sobrenome, a lista inteira precisa ser escaneada. Portanto, desenhar o índice requer entender exatamente quais colunas sua aplicação mais utiliza nas cláusulas WHERE, JOIN e ORDER BY do dia a dia.
A armadilha dos operadores de intervalo na ordem errada
Outro detalhe crítico que costuma derrubar a performance de sistemas em produção é o uso de operadores de intervalo, como >, <, BETWEEN ou LIKE '%termo'. Quando você coloca uma coluna que sofre filtragem por intervalo na primeira posição de um índice composto, você quebra a capacidade do MySQL de continuar usando as colunas seguintes para filtrar dados com precisão exata.
Imagine que você crie um índice estruturado como (data_pedido, status) e faça uma consulta buscando pedidos entre duas datas e com um status específico. Como a primeira coluna lida com uma faixa ampla de valores, o motor de busca perde o alinhamento estrito para a segunda coluna logo após o primeiro limite de intervalo. Para mitigar esse tipo de gargalo e garantir respostas rápidas em APIs pesadas, vale a pena conferir estratégias complementares, a exemplo de como otimizar consultas N mais 1 no PostgreSQL, que também tratam de eficiência no tráfego de dados.
A regra prática de ouro para posicionar colunas é: coloque primeiro as colunas que utilizam operadores de igualdade exata (como id = 15 ou status = 'ativo'). Somente depois disso posicione as colunas que recebem filtros de intervalo ou ordenações dinâmicas. Dessa forma, o motor do MySQL consegue navegar pelo índice com máxima precisão antes de aplicar os recortes mais amplos.
Passo a passo para identificar gargalos e criar o índice ideal
Se você desconfia que uma tabela massiva está sofrendo com buscas lentas por falta de índices compostos adequados, execute o procedimento abaixo para diagnosticar e resolver o problema de forma definitiva na sua aplicação. Para aprofundar esses conceitos na prática em produção, confira também nossa análise técnica sobre Por que o app React trava? Como eliminar renderizações e ganhar velocidade.
- Abra o terminal do seu cliente MySQL preferido ou ferramenta de administração e execute o comando EXPLAIN antes da sua consulta lenta para verificar se está ocorrendo um full table scan.
EXPLAIN SELECT * FROM pedidos WHERE cliente_id = 42 AND status = 'pendente'; - Analise a coluna 'type' e 'key' no resultado do EXPLAIN. Se o tipo retornar 'ALL' e a chave 'NULL', significa que o banco leu a tabela inteira sem usar índices.
-- Exemplo de saída indicando varredura completa indesejada - Crie o índice composto adequado posicionando a coluna de igualdade mais seletiva na primeira posição, aplicando o comando de alteração na tabela.
ALTER TABLE pedidos ADD INDEX idx_cliente_status (cliente_id, status);
Conclusão
Otimizar consultas lentas no MySQL com índices compostos não é uma questão de sorte, mas sim de alinhar a arquitetura do banco com o comportamento real das consultas da sua aplicação. Compreender a ordem correta das colunas e respeitar o prefixo esquerdo transforma tabelas pesadas e lentas em estruturas ágeis, capazes de responder em milissegundos mesmo sob alta concorrência.
Ao auditar regularmente seus planos de execução com o comando EXPLAIN e estruturar com cuidado os campos de igualdade antes dos intervalos, você garante a escalabilidade do sistema e evita que o crescimento orgânico da base de dados comprometa a experiência dos seus usuários.