Otimização

Como ler o EXPLAIN do MySQL 8 sem medo

Guia prático das colunas do EXPLAIN: type, key, rows, Extra e o que cada valor indica sobre a saúde do plano de execução.

O EXPLAIN é o raio-X do MySQL: mostra o caminho que o otimizador escolheu para executar a consulta. O problema é que o output assusta — 12 colunas, valores como ref_or_null, Using filesort. Este guia traduz cada coluna no que realmente importa.

O básico em 30 segundos

EXPLAIN
SELECT p.id, c.nome
FROM pedidos p
JOIN clientes c ON c.id = p.cliente_id
WHERE p.status = 'pago'
  AND p.criado_em >= '2026-06-01';

A saída tem uma linha por tabela na consulta. A ordem das linhas é a ordem de leitura — o MySQL processa de cima para baixo, então a primeira linha é a tabela “motora” da junção.

type: o termômetro do acesso

A coluna type diz como a tabela foi acessada. Do melhor ao pior:

  • const / eq_ref — acesso por chave única, no máximo uma linha. O cenário ideal.
  • ref — índice não único, poucas linhas. Saudável.
  • range — varredura de intervalo do índice (BETWEEN, >, <). Aceitável se o intervalo for seletivo.
  • index — varre o índice inteiro. Melhor que ALL, mas ainda é varredura completa.
  • ALLfull table scan. Lê a tabela inteira. Em tabela grande com frequência alta, é o suspeito número um de lentidão.

Regra prática: ALL em tabela com milhões de linhas consultada com frequência é bug de índice, não característica do banco.

key e rows: o que foi usado e o quanto foi lido

  • possible_keys — índices que o otimizador considerou.
  • key — índice efetivamente escolhido. NULL aqui com type = ALL confirma a varredura completa.
  • rows — estimativa de linhas examinadas. É estimativa, derivada das estatísticas de índice. Um rows muito maior que o resultado retornado indica baixa seletividade.
  • filtered — percentual das linhas examinadas que sobrevivem às demais condições. filtered = 1.11 com rows = 500000 significa meio milhão de linhas lidas para entregar poucas milhares.

Extra: os avisos que valem ouro

  • Using indexcovering index: a consulta foi resolvida inteira no índice, sem tocar a tabela. É o estado de graça.
  • Using where — filtro aplicado após a leitura. Normal, mas combinado com type = ALL é ruim.
  • Using filesort — ordenação fora do índice (ORDER BY sem índice que o cubra). Em consultas quentes, dói.
  • Using temporary — tabela temporária criada (comum em GROUP BY + JOIN). Vale investigar se aparece junto com filesort.
  • Using index conditionIndex Condition Pushdown funcionando: o filtro é aplicado no nível do índice antes de ler a linha. Bom sinal no MySQL 8.

Um diagnóstico completo em uma linha

type: ALL | key: NULL | rows: 1.2M | Extra: Using where; Using filesort

Tradução: varredura completa de 1,2 milhão de linhas, sem índice, filtrando depois de ler e ainda ordenando em memória/disco. Três problemas em uma consulta — e provavelmente um índice composto (status, criado_em) resolve os três de uma vez.

Conclusão

Leia o EXPLAIN nesta ordem: type primeiro (como acessou), key/rows depois (o que usou e quanto leu), Extra por último (avisos). Na dúvida, EXPLAIN ANALYZE mostra os tempos reais de cada operador. Quer ajuda para revisar os planos das suas consultas críticas? Veja os serviços de otimização da MySQL Box.