Explicando o MySQL Explain

O MySQL Explain é uma ferramenta usada explicar o plano de execução que o SGBD do MySQL usa para executar uma query. Com essa ferramenta é possível entender quais índices o banco utiliza na query, quais os relacionamentos usados, quantas linhas foram examidas para retornar os dados, se foi ou não necessário ler todos os dados da tabela.

Em que momentos posso usar o explain?

O EXPLAIN é muito útil nos seguintes cenários:
  • Quando você quer melhorar o desempenho de uma query
  • Quando você quer verificar se a query está utilizando o melhor plano de execução
  • Quando você quer verificar se a query está utilizando os índices corretos ou múltiplos índices
  • A query começa a ficar lenta para listar os registros de uma tela
  • A query performa bem em alguns momentos e outros nem tanto
  • O update de um ou mais registros começa a ficar lento

Como usar o EXPLAIN?

A syntaxe para o explain é simples, apenas adicione EXPLAIN antes da query que você quer estudar. Ex: EXPLAIN SELECT coluna1, coluna2 FROM tabela WHERE coluna3 = valor;. Pode ser qualquer tipo de query: SELECT, UPDATE, DELETE, INSERT.

Mas, temos também outras formas de usar como: EXPLAIN FORMAT=json QUERY;  ou  EXPLAIN FORMAT=json QUERY\G; para trazer o resultado formatado.

Campos do explain

Ao executar o EXPLAIN no MySQL, você verá um reusltado com os seguintes campos: id, select_type, table, possible_keys, key, key_len, ref, rows, filtered e extra. No formato json os campos mudam um pouco, mas trazem as mesmas informações, veja na tabela abaixo.

Column JSON Name Meaning
id select_id The SELECT identifier
select_type None The SELECT type
table table_name The table for the output row
partitions partitions The matching partitions
type access_type The join type
possible_keys possible_keys The possible indexes to choose
key key The index actually chosen
key_len key_length The length of the chosen key
ref ref The columns compared to the index
rows rows Estimate of rows to be examined
filtered filtered Percentage of rows filtered by table condition
Extra None Additional information
Para mais detalhes acesse https://dev.mysql.com/doc/refman/5.6/en/explain-output.html#explain-output-columns

Como analisar uma query com o MySQL Explain?

Primeiro, execute a query com o EXPLAIN.

        
          explain
          select
            a.first_name,
            a.last_name,
            f.title,
            f.description
          from
            actor a
          join film_actor fa ON
            fa.actor_id = a.actor_id
          join film f ON
            f.film_id = fa.film_id
          where
            a.first_name like 'A%';
        
        

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEa ALLPRIMARY   20011,11Using where
1SIMPLEfa refPRIMARY,idx_fk_film_idPRIMARY2sakila.a.actor_id27100Using index
1SIMPLEf eq_refPRIMARYPRIMARY2sakila.fa.film_id1100 

Com o resultado em mãos é hora de analisar os dados:

A coluna select_type indica qual o tipo de select foi feito. Ela é importante para saber se foi um select simpes, um union, uma subquery. Veja a lista completa aqui.

A coluna table indica a tabela examinada. Nessa coluna traz o alias utilizado para atabela ou nome da tabela caso nenhum alias seja utilizado.

A coluna type descreve como as tabelas são unidas. Essa coluna te ajuda a saber se na consulta está ocorrendo algum full table scan (escaneamento completo em alguma tabela) ou se os dados estão sendo selecionados por valor constante, index, por um range de valores. Entre os melhores valores para essa coluna temos system, const e eq_ref e entre os piores temos ALL e index, sendo ALL o pior de todos. Veja a lista completa aqui.

Outro campo que deve ser observado é o possible_keys e o key, eles indicam respectivamente quais os índices que o mysql pode usar para achar os registros e qual o índice o mysql usou para achar os registros.

Depois, olhe o campo ref, ela mostra quais colunas ou constantes são comparadas ao índice que aparece na coluna key que foram utilizados para selecionar as linhas da tabela.

Além desses, é importante olhar os campos rows e filtered. A coluna rows indica quantas linhas o MySQL acredita que precisa examinar para executar a query, enquanto que a coluna filtered indica uma porcentagem estimada de linhas da tabela que são filtradas pela condição da tabela.

Algumas dicas

  1. A coluna rows x filtered indica a quantidade de linhas examinadas. Ex: no caso acima a primeira linha traz que 200 na coluna rows e 11.11 (11.11%) na coluna filtered, então, a quantidade de linhas examinadas foi 200 x 11.11% = 22,22.
  2. O número total de linhas examinadas é o produto da coluna rows de cada linha. No caso acima a conta seria 200 x 27 x 1 = 5400.
  3. Fique atento a coluna key_len, ela indica o tamnho do índice. O MySQL pode usar índices em colunas com mais eficiência se forem declarados como do mesmo tipo e tamanho.
    1. VARCHAR e CHAR são considerados os mesmos se declarados com o mesmo tamanho. ex: VARCHAR(10) e CHAR(10)
  4. Verifique se o índice usado na consulta é o ideal. O MySQL trabalha para usar sempre o melhor índice, mas é sempre bom verificar.
  5. Nem sempre adicionar um novo íncide vai ajudar, então faça sempre testes.
  6. Nos testes de query use SHOW STATUS LIKE 'Last_Query_Cost'; (dica do meu brother Felipe Borges). Execute esse comando após ter executado alguma query, o query cost não tem uma unidade de medida, o que você precisa saber é que quanto maior pior, a partir do MySQL 5.7, esse valor é exibido na coluna cost ao executar o EXPLAIN
  7. Verifique se a consulta pode ser feita usado algum outro campo que possúi índice. No caso acima se mudarmos a pesquisa para usar o campo last_name o número de linhas examinadas deiminui drasticamente 7×27×1 = 189.
              
                explain
                select
                  a.first_name,
                  a.last_name,
                  f.title,
                  f.description
                from
                  actor a
                join film_actor fa ON
                  fa.actor_id = a.actor_id
                join film f ON
                  f.film_id = fa.film_id
                where
                  a.last_name like 'A%';
              
              
    idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
    1SIMPLEa rangePRIMARY,idx_actor_last_nameidx_actor_last_name137 7100Using index condition
    1SIMPLEfa refPRIMARY,idx_fk_film_idPRIMARY2sakila.a.actor_id27100Using index
    1SIMPLEf eq_refPRIMARYPRIMARY2sakila.fa.film_id1100 

Por hoje é só...

anúncio