Sintaxe de EXPLAIN (Obter informações sobre uma SELECT)


EXPLAIN nome_tabela é um sinônimo para DESCRIBE nome_tabela ou SHOW COLUMNS FROM nome_tabela.

Quando uma instrução SELECT for precedida da palavra chave EXPLAIN, o MariaDB explicará como ele deve processar a SELECT, fornecendo informação sobre como as tabelas estão sendo unidas e em qual ordem.

Com a ajuda de EXPLAIN, você pode ver quando devem ser adicionados índices à tabelas para obter uma SELECT mais rápida que utiliza índices para encontrar os registros.

Voce deve executar frequentemente ANALYZE TABLE para atualizar estatísticas de tabela tais como a cardinalidade das chaves que podem afetar a escolha que o otimizador faz. Leia "Sintaxe de ANALYZE TABLE".

Você também pode ver se o otimizador une as tabelas em uma melhor ordem. Para forçar o otimizador a utilizar uma ordem específica de join para uma instrução SELECT, adicione uma cláusula STRAIGHT_JOIN.

Para ligações mais complexas, EXPLAIN retorna uma linha de informação para cada tabela utilizada na instrução SELECT. As tabelas são listadas na ordem que seriam lidas. O MariaDB soluciona todas as joins utilizando um método multi-join de varedura simples. Isto significa que o MariaDB lê uma linha da primeira tabela, depois encontra uma linha que combina na segunda tabela, depois na terceira tabela e continua. Quando todas tabelas são processadas, ele exibe as colunas selecionadas e recua através da lista de tabelas até uma tabela na qual existem registros coincidentes for encontrada. O próximo registro é lido desta tabela e o processo continua com a próxima tabela.

No MariaDB versão 4.1 a saída do EXPLAIN foi alterada para funcionar melhor com construções como UNIONs, subqueries e tabelas derivadas. A mais notável é a adição de duas novas colunas: id e select_type.

A saída de EXPLAIN inclui as seguintes colunas:

Você pode ter uma boa indicação de quão boa é sua join multiplicando todos os valores na coluna rows na saída de EXPLAIN. Isto deve dizer a grosso modo quantos registros o MariaDB deve examinar para executar a consulta. Este número é também usado quando você restringe consultas com a variável max_join_size. Leia "Parâmetros de Sintonia do Servidor".

O exemplo a seguir mostra como um JOIN pode ser otimizado progressivamente utilizando a informação fornecida por EXPLAIN.

Suponha que você tem a instrução SELECT exibida abaixo, que você está examinando utilizando EXPLAIN:

EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
 tt.ProjectReference, tt.EstimatedShipDate,
 tt.ActualShipDate, tt.ClientID,
 tt.ServiceCodes, tt.RepetitiveID,
 tt.CurrentProcess, tt.CurrentDPPerson,
 tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
 et_1.COUNTRY, do.CUSTNAME
 FROM tt, et, et AS et_1, do
 WHERE tt.SubmitTime IS NULL
 AND tt.ActualPC = et.EMPLOYID
 AND tt.AssignedPC = et_1.EMPLOYID
 AND tt.ClientID = do.CUSTNMBR;

Para este exemplo, assuma que:

Initially, before any optimizations have been performed, the EXPLAIN statement produces the following information:

table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74
do ALL PRIMARY NULL NULL NULL 2135
et_1 ALL PRIMARY NULL NULL NULL 74
tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872
 range checked for each record (key map: 35)

Como o tipo é ALL em todas tabelas, esta saída indica que o MariaDB está gerando um produto Cartesiano de todas as tabelas! Isto levará muito tempo para ser executado, pois o produto do número de registros em cada tabela deve ser examinado ! Neste caso, existem * 2135 * 74 * 3872 registros. Se as tabelas forem maiores, imagine quanto tempo este tipo de consulta pode demorar.

Um dos problemas aqui é que o MariaDB não pode (ainda) utilizar índices em colunas de maneira eficiente se elas foram declaras ide forma diferente. Neste contexto, VARCHAR e CHAR são o mesmo a menos que tenham sido declarados com tamanhos diferentes. Como tt.ActualPC é declarado como CHAR(10) e et.EMPLOYID é declarado como CHAR(15), existe aqui uma diferença de tamanho.

Para corrigir esta diferença entre tamanhos de registros, utilize ALTER TABLE para alterar o tamanho de ActualPC de 10 para 15 caracteres:

mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);

Agora ambos campos tt.ActualPC e et.EMPLOYID são VARCHAR(15). Executando a instrução EXPLAIN novamente produzirá este resultado:

table type possible_keys key key_len ref rows Extra tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 Using where do ALL PRIMARY NULL NULL NULL 2135
 range checked for each record (key map: 1)
et_1 ALL PRIMARY NULL NULL NULL 74
 range checked for each record (key map: 1)
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1

Isto não está perfeito, mas está bem melhor ( o produto dos valores de rows agora menor por um fator de 74 ). Esta versão é executada em vários segundos.

Uma segunda alteração pode ser feita para eliminar as diferenças de tamanho das colunas para as comparações tt.AssignedPC = et_1.EMPLOYID e tt.ClientID = do.CUSTNMBR :

mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
 -> MODIFY ClientID VARCHAR(15);

Agora EXPLAIN produz a saída mostrada abaixo:

table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74
tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 Using where
 ClientID,
 ActualPC et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1

Este resultado é quase o melhor que se pode obter.

O problema restante é que, por padrão, o MariaDB assume que valores na coluna tt.ActualPC estão distribuídos igualmente, e este não é o caso para a tabela tt. Felizmente, é fácil informar ao MariaDB sobre isto:

shell> myisamchk --analyze PATH_TO_MYSQL_DATABASE/tt
shell> mysqladmin refresh

Agora a join está perfeita, e EXPLAIN produz esta saída:

table type possible_keys key key_len ref rows Extra tt ALL AssignedPC NULL NULL NULL 3872 Using where
 ClientID,
 ActualPC et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1

Perceba que a coluna rows na saída de EXPLAIN é uma boa ajuda para otimizador de joins do MariaDB. Para otimizar uma consulta, você deve conferir se os números estão perto da realidade. Se não, você pode obter melhor desempenho utilizando STRAIGHT_JOIN em sua instrução SELECT e tentar listar as tabelas em uma ordem diferente na cláusula FROM.

Retornar