Desenvolvedores frequentemente me fazem a mesma pergunta: "Minha API está lenta. Por onde eu começo?" O reflexo costuma ser fazer um upgrade no servidor ou dobrar a RAM. Isso custa dinheiro e raramente resolve a causa raiz. Na maioria das aplicações Laravel, o gargalo reside na camada do banco de dados. A sintaxe elegante do framework torna fácil esquecer que cada chamada Eloquent eventualmente se torna SQL, e que o SQL é, muitas vezes, onde a dor começa.
Antes de mexer em qualquer configuração de servidor, analise suas consultas metodicamente.
Comece com o Diagnóstico Correto
Não otimize no escuro. Reescrever consultas aleatoriamente é um palpite, e palpites desperdiçam horas.
Você precisa encontrar as instruções que consomem o maior tempo total. Observe sua aplicação sob carga real. O Laravel Telescope oferece uma visão limpa de cada consulta executada durante uma requisição, com o tempo de execução anexado. O Laravel Debugbar as exibe no seu navegador durante o desenvolvimento local para que você possa identificar anomalias imediatamente. Quando precisar capturar problemas em produção, habilite o MySQL Slow Query Log. Ele registra instruções que excedem um limite definido por você, o que o torna ideal para encontrar surpresas que não aparecem em conjuntos de dados pequenos. Se você estiver executando algo maior, uma ferramenta de Application Performance Monitoring pode correlacionar endpoints HTTP lentos com chamadas de banco de dados específicas.
Ao revisar os dados, procure por duas coisas: tempo de execução absoluto e frequência de chamadas. Uma consulta que leva quarenta milissegundos parece inofensiva até você perceber que ela é executada duas mil vezes por minuto. Um relatório de três segundos que roda uma vez por hora pode importar menos do que uma busca de meio segundo que roda em cada página. Corrija primeiro os problemas de alto impacto.
Pare de Pedir Tudo
SELECT * é conveniente. Também é caro. Quando você escreve Model::all() ou busca um conjunto de resultados sem nomear as colunas, o MySQL carrega todos os campos de cada linha correspondente. Isso inclui campos de texto grandes, blobs JSON e qualquer outra coisa presente na tabela. O conjunto de resultados cresce, o uso de memória aumenta e o tempo gasto serializando a resposta aumenta.
Seja explícito. Se o seu controller precisa apenas dos campos id, name e email, solicite exatamente esses:
User::select('id', 'name', 'email')->get();
No query builder, o mesmo princípio se aplica. Payloads menores se movem mais rápido pela rede e consomem menos RAM no seu servidor de aplicação. Esta é uma das vitórias mais baratas disponíveis, mas é fácil ignorá-la porque o Laravel torna o SELECT * o comportamento padrão.
Deixe o EXPLAIN Guiar suas Mudanças
Nunca refatore uma consulta lenta sem executar o EXPLAIN primeiro. No MySQL, a palavra-chave EXPLAIN mostra o plano de execução da consulta. Ela revela exatamente como o otimizador pretende encontrar seus dados.
Preste atenção à coluna type. Se você vir ALL, o MySQL está realizando um scan completo na tabela (full table scan). Isso significa que ele está lendo cada linha para satisfazer sua cláusula WHERE. Olhe para a coluna key para ver se o otimizador está usando algum índice. Em seguida, verifique a coluna Extra. Se você encontrar Using temporary ou Using filesort, o MySQL está construindo tabelas intermediárias ou ordenando em memória porque sua estrutura atual não consegue satisfazer a consulta de forma eficiente.
Execute o EXPLAIN no seu cliente MySQL ou use uma ferramenta que formate a saída para você. Assim que vir o plano, você saberá se o problema é um índice ausente, um join ruim ou um predicado que o mecanismo não consegue otimizar. A adivinhação torna-se desnecessária.
Indexe com Intenção
Índices são a ferramenta mais poderosa para acelerar buscas, mas eles só funcionam quando correspondem à forma como você consulta. Sem o índice correto, o MySQL percorre linha por linha. Isso pode parecer aceitável em desenvolvimento em uma tabela com mil linhas, mas pode colapsar em produção em uma tabela com dez milhões.
Comece com índices de coluna única para campos que aparecem frequentemente em cláusulas WHERE. Se você filtra constantemente por status, adicione um índice em status.
Quando uma consulta filtra várias colunas juntas, passe para índices compostos. A ordem das colunas dentro do índice importa porque o MySQL lê índices compostos da esquerda para a direita. Isso é chamado de regra do prefixo à esquerda (leftmost prefix rule). Se sua consulta pesquisa por user_id e depois ordena por created_at, um índice composto em (user_id, created_at) ajuda significativamente. Inverta a ordem e o otimizador pode nem usar o índice para o filtro.
Não indexe todas as colunas. Cada índice adiciona overhead a inserts, updates e deletes porque o MySQL deve manter a estrutura. Adicione-os deliberadamente com base nos padrões que você encontrou durante a medição.
Mantenha Funções Longe das Colunas
Este erro desativa índices silenciosamente. Quando você envolve uma coluna em uma função dentro de uma cláusula WHERE, o MySQL não consegue
