MySQL-explain

来自技术开发小组内部wiki
跳转至: 导航搜索
一、语法
{EXPLAIN | DESCRIBE | DESC}
    tbl_name [col_name | wild]

{EXPLAIN | DESCRIBE | DESC}
    [explain_type] SELECT select_options

explain_type: {EXTENDED | PARTITIONS}

示例:
explain employees;
+------------+---------------+------+-----+---------+-------+
| Field      | Type          | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| emp_no     | int(11)       | NO   | PRI | NULL    |       |
| birth_date | date          | NO   |     | NULL    |       |
| first_name | varchar(14)   | NO   |     | NULL    |       |
| last_name  | varchar(16)   | NO   |     | NULL    |       |
| gender     | enum('M','F') | NO   |     | NULL    |       |
| hire_date  | date          | NO   |     | NULL    |       |
+------------+---------------+------+-----+---------+-------+

explain select * from employees where emp_no=10001;
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | employees | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+

explain extended select * from employees where emp_no=10001;show warnings;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                    |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | select '10001' AS `emp_no`,'1953-09-02' AS `birth_date`,'Georgi' AS `first_name`,'Facello' AS `last_name`,'M' AS `gender`,'1986-06-26' AS `hire_date` from `employees`.`employees` where 1 |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

explain extended select * from employees where first_name='Georgi' and first_name like 'Geo%';show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                                                                                                               |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | select `employees`.`employees`.`emp_no` AS `emp_no`,`employees`.`employees`.`birth_date` AS `birth_date`,`employees`.`employees`.`first_name` AS `first_name`,`employees`.`employees`.`last_name` AS `last_name`,`employees`.`employees`.`gender` AS `gender`,`employees`.`employees`.`hire_date` AS `hire_date` from `employees`.`employees` where (`employees`.`employees`.`first_name` = 'Georgi') |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

二、输出列
+----+-------------+----------+------+----------------+---------+---------+-------+------+-------+
| id | select_type | table    | type | possible_keys  | key     | key_len | ref   | rows | Extra |
+----+-------------+----------+------+----------------+---------+---------+-------+------+-------+

1)id:

示例:
explain select 'Georgi','Facello',dept_name
  from departments
 where dept_no in
       (select dept_no
          from dept_emp
         where emp_no in
               (select emp_no from employees where first_name = 'Georgi' and last_name = 'Facello'));
+----+--------------------+-------------+-----------------+---------------+-----------+---------+------+-------+--------------------------+
| id | select_type        | table       | type            | possible_keys | key       | key_len | ref  | rows  | Extra                    |
+----+--------------------+-------------+-----------------+---------------+-----------+---------+------+-------+--------------------------+
|  1 | PRIMARY            | departments | index           | NULL          | dept_name | 122     | NULL |     9 | Using where; Using index |
|  2 | DEPENDENT SUBQUERY | dept_emp    | index_subquery  | dept_no       | dept_no   | 12      | func | 41485 | Using index; Using where |
|  3 | DEPENDENT SUBQUERY | employees   | unique_subquery | PRIMARY       | PRIMARY   | 4       | func |     1 | Using where              |
+----+--------------------+-------------+-----------------+---------------+-----------+---------+------+-------+--------------------------+

explain select a.first_name, a.last_name, c.dept_name
  from employees a, dept_emp b, departments c
 where a.emp_no = b.emp_no
   and b.dept_no = c.dept_no
   and a.first_name = 'Georgi'
   and a.last_name = 'Facello';
+----+-------------+-------+--------+------------------------+-----------+---------+---------------------+-------+-------------+
| id | select_type | table | type   | possible_keys          | key       | key_len | ref                 | rows  | Extra       |
+----+-------------+-------+--------+------------------------+-----------+---------+---------------------+-------+-------------+
|  1 | SIMPLE      | c     | index  | PRIMARY                | dept_name | 122     | NULL                |     9 | Using index |
|  1 | SIMPLE      | b     | ref    | PRIMARY,emp_no,dept_no | dept_no   | 12      | employees.c.dept_no | 41485 | Using index |
|  1 | SIMPLE      | a     | eq_ref | PRIMARY                | PRIMARY   | 4       | employees.b.emp_no  |     1 | Using where |
+----+-------------+-------+--------+------------------------+-----------+---------+---------------------+-------+-------------+


2)select_type:

SIMPLE	Simple SELECT (not using UNION or subqueries)
PRIMARY	Outermost SELECT
UNION	Second or later SELECT statement in a UNION
DEPENDENT UNION	Second or later SELECT statement in a UNION, dependent on outer query
UNION RESULT	Result of a UNION.
SUBQUERY	First SELECT in subquery
DEPENDENT SUBQUERY	First SELECT in subquery, dependent on outer query
DERIVED	Derived table SELECT (subquery in FROM clause)
UNCACHEABLE SUBQUERY	A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query
UNCACHEABLE UNION	The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY)


示例:
explain select * from employees where emp_no=10001 or emp_no=10002;
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | range | PRIMARY       | PRIMARY | 4       | NULL |    2 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+

explain select * from employees a where emp_no=10001 union all select * from employees b where emp_no=10002;
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type  | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------+
|  1 | PRIMARY      | a          | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
|  2 | UNION        | b          | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
| NULL | UNION RESULT | <union1,2> | ALL   | NULL          | NULL    | NULL    | NULL  | NULL |       |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------+

explain select * from employees b
 where emp_no in
       (select emp_no from dept_emp c where dept_no = 'd001'
        union all
        select emp_no from dept_emp d where dept_no = 'd002');
+----+--------------------+------------+------+------------------------+---------+---------+------+--------+--------------------------+
| id | select_type        | table      | type | possible_keys          | key     | key_len | ref  | rows   | Extra                    |
+----+--------------------+------------+------+------------------------+---------+---------+------+--------+--------------------------+
|  1 | PRIMARY            | b          | ALL  | NULL                   | NULL    | NULL    | NULL | 299920 | Using where              |
|  2 | DEPENDENT SUBQUERY | c          | ref  | PRIMARY,emp_no,dept_no | PRIMARY | 4       | func |      1 | Using where; Using index |
|  3 | DEPENDENT UNION    | d          | ref  | PRIMARY,emp_no,dept_no | PRIMARY | 4       | func |      1 | Using where; Using index |
| NULL | UNION RESULT       | <union2,3> | ALL  | NULL                   | NULL    | NULL    | NULL |   NULL |                          |
+----+--------------------+------------+------+------------------------+---------+---------+------+--------+--------------------------+

explain select * from dept_emp where dept_no = ( select dept_no from dept_emp where dept_no=@@sql_log_bin);
+----+----------------------+----------+-------+---------------+--------+---------+------+--------+-----------------------------------------------------+
| id | select_type          | table    | type  | possible_keys | key    | key_len | ref  | rows   | Extra                                               |
+----+----------------------+----------+-------+---------------+--------+---------+------+--------+-----------------------------------------------------+
|  1 | PRIMARY              | NULL     | NULL  | NULL          | NULL   | NULL    | NULL |   NULL | Impossible WHERE noticed after reading const tables |
|  2 | UNCACHEABLE SUBQUERY | dept_emp | index | dept_no       | emp_no | 4       | NULL | 331883 | Using where; Using index                            |
+----+----------------------+----------+-------+---------------+--------+---------+------+--------+-----------------------------------------------------+

explain select * from (select * from employees b where emp_no=10001) a;
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL    | NULL    | NULL |    1 |       |
|  2 | DERIVED     | b          | const  | PRIMARY       | PRIMARY | 4       |      |    1 |       |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+


3)table:
tablename
<derivedN>
<unionM,N>

示例:
explain select * from (select * from employees b where emp_no=10001) a;
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL    | NULL    | NULL |    1 |       |
|  2 | DERIVED     | b          | const  | PRIMARY       | PRIMARY | 4       |      |    1 |       |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+

explain select * from employees a where emp_no=10001 union all select * from employees b where emp_no=10002;
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type  | table      | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------+
|  1 | PRIMARY      | a          | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
|  2 | UNION        | b          | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
| NULL | UNION RESULT | <union1,2> | ALL   | NULL          | NULL    | NULL    | NULL  | NULL |       |
+----+--------------+------------+-------+---------------+---------+---------+-------+------+-------+


4)type:
system	The table has only one row (= system table).This is a special case of the const join type.
const	is used when you compare all parts of a PRIMARY KEY or UNIQUE index to constant values. 
eq_ref	One row is read from this table for each combination of rows from the previous tables.
ref	All rows with matching index values are read from this table for each combination of rows from the previous tables.
ref_or_null	This join type is like ref, but with the addition that MySQL does an extra search for rows that contain NULL values. 
fulltext	The join is performed using a FULLTEXT index.
index_merge	This join type indicates that the Index Merge optimization is used.
unique_subquery	This type replaces ref for some IN subqueries of the following form:value IN (SELECT primary_key FROM single_table WHERE some_expr),unique_subquery is just an index lookup function that replaces the subquery completely for better efficiency.
index_subquery	This join type is similar to unique_subquery. It replaces IN subqueries, but it works for nonunique indexes in subqueries of the following form:value IN (SELECT key_column FROM single_table WHERE some_expr)
range	Only rows that are in a given range are retrieved, using an index to select the rows.range can be used when a key column is compared to a constant using any of the =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, or IN() operators:
index	The index join type is the same as ALL, except that the index tree is scanned. 
ALL	A full table scan is done for each combination of rows from the previous tables.

示例:
explain select * from (select * from employees b where emp_no=10001 limit 1) a;
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL    | NULL    | NULL |    1 |       |
|  2 | DERIVED     | b          | const  | PRIMARY       | PRIMARY | 4       |      |    1 |       |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+

explain select a.first_name, a.last_name, c.dept_name
  from employees a, dept_emp b, departments c
 where a.emp_no = b.emp_no
   and b.dept_no = c.dept_no
   and a.first_name = 'Georgi'
   and a.last_name = 'Facello';
+----+-------------+-------+--------+------------------------+-----------+---------+---------------------+-------+-------------+
| id | select_type | table | type   | possible_keys          | key       | key_len | ref                 | rows  | Extra       |
+----+-------------+-------+--------+------------------------+-----------+---------+---------------------+-------+-------------+
|  1 | SIMPLE      | c     | index  | PRIMARY                | dept_name | 122     | NULL                |     9 | Using index |
|  1 | SIMPLE      | b     | ref    | PRIMARY,emp_no,dept_no | dept_no   | 12      | employees.c.dept_no | 41485 | Using index |
|  1 | SIMPLE      | a     | eq_ref | PRIMARY                | PRIMARY   | 4       | employees.b.emp_no  |     1 | Using where |
+----+-------------+-------+--------+------------------------+-----------+---------+---------------------+-------+-------------+

explain select dept_no, dept_name from departments1 where dept_name = 'Sales' or dept_name is null;
+----+-------------+--------------+-------------+---------------+-----------+---------+-------+------+--------------------------+
| id | select_type | table        | type        | possible_keys | key       | key_len | ref   | rows | Extra                    |
+----+-------------+--------------+-------------+---------------+-----------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | departments1 | ref_or_null | dept_name     | dept_name | 123     | const |    4 | Using where; Using index |
+----+-------------+--------------+-------------+---------------+-----------+---------+-------+------+--------------------------+

create fulltext index idx_dept2_name on departments2(dept_name);
explain select dept_no, dept_name from departments2 where match(dept_name) against('Sal' in boolean mode);
+----+-------------+--------------+----------+----------------+----------------+---------+------+------+-------------+
| id | select_type | table        | type     | possible_keys  | key            | key_len | ref  | rows | Extra       |
+----+-------------+--------------+----------+----------------+----------------+---------+------+------+-------------+
|  1 | SIMPLE      | departments2 | fulltext | idx_dept2_name | idx_dept2_name | 0       |      |    1 | Using where |
+----+-------------+--------------+----------+----------------+----------------+---------+------+------+-------------+

explain select * from employees1 where first_name='Georgi' or last_name='Peac'
+----+-------------+------------+-------------+----------------------+----------------------+---------+------+------+------------------------------------------------+
| id | select_type | table      | type        | possible_keys        | key                  | key_len | ref  | rows | Extra                                          |
+----+-------------+------------+-------------+----------------------+----------------------+---------+------+------+------------------------------------------------+
|  1 | SIMPLE      | employees1 | index_merge | first_name,last_name | first_name,last_name | 44,50   | NULL |  435 | Using union(first_name,last_name); Using where |
+----+-------------+------------+-------------+----------------------+----------------------+---------+------+------+------------------------------------------------+

explain select * from dept_emp where emp_no in(select emp_no from employees where first_name='Georgi' or last_name='Peac');
+----+--------------------+-----------+-----------------+---------------+---------+---------+------+--------+-------------+
|  1 | PRIMARY            | dept_emp  | ALL             | NULL          | NULL    | NULL    | NULL | 331883 | Using where |
|  2 | DEPENDENT SUBQUERY | employees | unique_subquery | PRIMARY       | PRIMARY | 4       | func |      1 | Using where |
+----+--------------------+-----------+-----------------+---------------+---------+---------+------+--------+-------------+

explain select * from employees where first_name in(select first_name from employees1 where first_name='Georgi' or last_name='Peac');
+----+--------------------+------------+----------------+----------------------+------------+---------+------+--------+-------------+
| id | select_type        | table      | type           | possible_keys        | key        | key_len | ref  | rows   | Extra       |
+----+--------------------+------------+----------------+----------------------+------------+---------+------+--------+-------------+
|  1 | PRIMARY            | employees  | ALL            | NULL                 | NULL       | NULL    | NULL | 299920 | Using where |
|  2 | DEPENDENT SUBQUERY | employees1 | index_subquery | first_name,last_name | first_name | 44      | func |      1 | Using where |
+----+--------------------+------------+----------------+----------------------+------------+---------+------+--------+-------------+

explain select * from employees where emp_no<10002;
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | employees | range | PRIMARY       | PRIMARY | 4       | NULL |    1 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+------+-------------+

explain select emp_no from employees;
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows   | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
|  1 | SIMPLE      | employees | index | NULL          | PRIMARY | 4       | NULL | 299920 | Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+

explain select * from employees;
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------+
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 299920 |       |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------+


5)possible_keys
The possible_keys column indicates which indexes MySQL can choose from use to find the rows in this table. 

6)key
The key column indicates the key (index) that MySQL actually decided to use.

7)key_len
The key_len column indicates the length of the key that MySQL decided to use. 

8)ref
The ref column shows which columns or constants are compared to the index named in the key column to select rows from the table.

9)rows
The rows column indicates the number of rows MySQL believes it must examine to execute the query.

10)Extra
This column contains additional information about how MySQL resolves the query.

Child of 'table' pushed join@1
const row not found
Distinct
Full scan on NULL key
Impossible HAVING
Impossible WHERE
Impossible WHERE noticed after reading const tables
No matching min/max row
no matching row in const table
No tables used
Not exists
Range checked for each record (index map: N)
Scanned N databases
Select tables optimized away
Skip_open_table, Open_frm_only, Open_trigger_only, Open_full_table
unique row not found
Using filesort
Using index
Using index for group-by
Using join buffer
Using sort_union(...), Using union(...), Using intersect(...)
Using temporary
Using where
Using where with pushed condition


Using filesort、Using temporary

示例:


参考:http://dev.mysql.com/doc/refman/5.5/en/using-explain.html


以下补充:
select @@profiling;
set profiling=1;

执行 select 语句

show profiles;
show profile for query N;

示例:
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000113 |
| checking permissions | 0.000006 |
| checking permissions | 0.000002 |
| checking permissions | 0.000027 |
| Opening tables       | 0.000027 |
| System lock          | 0.000012 |
| init                 | 0.000030 |
| optimizing           | 0.000020 |
| statistics           | 0.000075 |
| preparing            | 0.000025 |
| executing            | 0.000004 |
| Sending data         | 0.362112 |
| end                  | 0.000011 |
| query end            | 0.000004 |
| closing tables       | 0.000009 |
| freeing items        | 0.000517 |
| logging slow query   | 0.000004 |
| cleaning up          | 0.000004 |
+----------------------+----------+