-- id 全相同 mysql root@localhost:employees> explain select * from employees e,dept_emp d,departments de where e.emp_no = d.emp_no and de.dept_name = 'Human Resources';
+----+-------------+-------+------------+-------+---------------+-----------+---------+--------------------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+-----------+---------+--------------------+--------+----------+-------------+ | 1 | SIMPLE | de | <null> | const | dept_name | dept_name | 122 | const | 1 | 100.0 | Using index | | 1 | SIMPLE | e | <null> | ALL | PRIMARY | <null> | <null> | <null> | 299512 | 100.0 | <null> | | 1 | SIMPLE | d | <null> | ref | PRIMARY | PRIMARY | 4 | employees.e.emp_no | 1 | 100.0 | <null> | +----+-------------+-------+------------+-------+---------------+-----------+---------+--------------------+--------+----------+-------------+ 3 rows in set Time: 0.018s
-- id 全不相同 mysql root@localhost:employees> explain select * from employees e where e.emp_no = (select d.emp_no from dept_emp d where d.dept_no = (select de.d ept_no from departments de where de.dept_name = 'Development') and d.emp_no = 10023); +----+-------------+-------+------------+-------+-----------------+-----------+---------+-------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+-----------------+-----------+---------+-------------+------+----------+-------------+ | 1 | PRIMARY | e | <null> | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.0 | <null> | | 2 | SUBQUERY | d | <null> | const | PRIMARY,dept_no | PRIMARY | 16 | const,const | 1 | 100.0 | Using index | | 3 | SUBQUERY | de | <null> | const | dept_name | dept_name | 122 | const | 1 | 100.0 | Using index | +----+-------------+-------+------------+-------+-----------------+-----------+---------+-------------+------+----------+-------------+ 3 rows in set Time: 0.027s
-- id 部分相同,部分不相同 mysql root@localhost:employees> explain select * from^Iemployees e where^Ie.emp_no in (select d.emp_no from dept_emp d where d.dept_no = (select d e.dept_no from departments de where de.dept_name = 'Human Resources')); +----+-------------+-------+------------+--------+-----------------+-----------+---------+--------------------+-------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+-----------------+-----------+---------+--------------------+-------+----------+-------------+ | 1 | PRIMARY | d | <null> | ref | PRIMARY,dept_no | dept_no | 12 | const | 33212 | 100.0 | Using index | | 1 | PRIMARY | e | <null> | eq_ref | PRIMARY | PRIMARY | 4 | employees.d.emp_no | 1 | 100.0 | <null> | | 3 | SUBQUERY | de | <null> | const | dept_name | dept_name | 122 | const | 1 | 100.0 | Using index | +----+-------------+-------+------------+--------+-----------------+-----------+---------+--------------------+-------+----------+-------------+ 3 rows in set Time: 0.020s
select_type
select_type 为表查询的类型,根据官方文档总结几种常见类型如下表:
SIMPLE:最常见的查询类型,通常情况下没有子查询、union 查询就是 SIMPLE 类型。
1 2 3 4 5 6 7 8
mysql root@localhost:employees> explain select * from employees where emp_no = 10001; +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+--------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+--------+ | 1 | SIMPLE | employees | <null> | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.0 | <null> | +----+-------------+-----------+------------+-------+---------------+---------+---------+-------+------+----------+--------+ 1 row in set Time: 0.019s
PRIMARY 和 SUBQUERY:在含有子查询的语句中会出现。
1 2 3 4 5 6 7 8 9 10
mysql root@localhost:employees> explain select * from dept_emp d where d.dept_no = (select de.dept_no from departments de where de.dept_name = 'De velopment'); +----+-------------+-------+------------+-------+---------------+-----------+---------+-------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+-----------+---------+-------+--------+----------+-------------+ | 1 | PRIMARY | d | <null> | ref | dept_no | dept_no | 12 | const | 148054 | 100.0 | Using where | | 2 | SUBQUERY | de | <null> | const | dept_name | dept_name | 122 | const | 1 | 100.0 | Using index | +----+-------------+-------+------------+-------+---------------+-----------+---------+-------+--------+----------+-------------+ 2 rows in set Time: 0.021s
UNION 和 UNION RESULT:在有 union 查询的语句中出现。
1 2 3 4 5 6 7 8 9 10
mysql root@localhost:employees> explain select * from departments where dept_no = 'd005' union select * from departments where dept_no = 'd004'; +--------+--------------+-------------+------------+-------+---------------+---------+---------+--------+--------+----------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +--------+--------------+-------------+------------+-------+---------------+---------+---------+--------+--------+----------+-----------------+ | 1 | PRIMARY | departments | <null> | const | PRIMARY | PRIMARY | 12 | const | 1 | 100.0 | <null> | | 2 | UNION | departments | <null> | const | PRIMARY | PRIMARY | 12 | const | 1 | 100.0 | <null> | | <null> | UNION RESULT | <union1,2> | <null> | ALL | <null> | <null> | <null> | <null> | <null> | <null> | Using temporary | +--------+--------------+-------------+------------+-------+---------------+---------+---------+--------+--------+----------+-----------------+ 3 rows in set Time: 0.020s
DEPENDENT UNION 和 DEPENDENT SUBQUERY:当语句中子查询和 union 查询依赖外部查询会出现。
1 2 3 4 5 6 7 8 9 10 11 12
mysql root@localhost:employees> explain select * from employees e where e.emp_no in (select d.emp_no from dept_emp d where d.from_date = '1986-06- 26' union select d.emp_no from dept_emp d where d.from_date = '1996-08-03'); +--------+--------------------+------------+------------+------+---------------+---------+---------+--------+--------+----------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +--------+--------------------+------------+------------+------+---------------+---------+---------+--------+--------+----------+-----------------+ | 1 | PRIMARY | e | <null> | ALL | <null> | <null> | <null> | <null> | 299512 | 100.0 | Using where | | 2 | DEPENDENT SUBQUERY | d | <null> | ref | PRIMARY | PRIMARY | 4 | func | 1 | 10.0 | Using where | | 3 | DEPENDENT UNION | d | <null> | ref | PRIMARY | PRIMARY | 4 | func | 1 | 10.0 | Using where | | <null> | UNION RESULT | <union2,3> | <null> | ALL | <null> | <null> | <null> | <null> | <null> | <null> | Using temporary| +--------+--------------------+------------+------------+------+---------------+---------+---------+--------+--------+----------+-----------------+ 4 rows in set Time: 0.022s
DERIVED:当查询涉及生成临时表时出现。
1 2 3 4 5 6 7 8 9
mysql root@localhost:employees> explain select * from (select * from departments limit 5) de; +----+-------------+-------------+------------+-------+---------------+-----------+---------+--------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+-------+---------------+-----------+---------+--------+------+----------+-------------+ | 1 | PRIMARY | <derived2> | <null> | ALL | <null> | <null> | <null> | <null> | 5 | 100.0 | <null> | | 2 | DERIVED | departments | <null> | index | <null> | dept_name | 122 | <null> | 9 | 100.0 | Using index | +----+-------------+-------------+------------+-------+---------------+-----------+---------+--------+------+----------+-------------+ 2 rows in set Time: 0.012s
mysql root@localhost:employees> set optimizer_switch='mrr=on,mrr_cost_based=off'; Query OK, 0 rows affected Time: 0.001s mysql root@localhost:employees> explain select * from employees where birth_date = '1970-01-01' and hire_date > '1990-01-01'; +----+-------------+-----------+------------+-------+----------------+----------------+---------+--------+------+----------+----------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+----------------+----------------+---------+--------+------+----------+----------------------------------+ | 1 | SIMPLE | employees | <null> | range | idx_birth_hire | idx_birth_hire | 6 | <null> | 1 | 100.0 | Using index condition; Using MRR | +----+-------------+-----------+------------+-------+----------------+----------------+---------+--------+------+----------+----------------------------------+ 1 row in set Time: 0.014s
Range checked for each record (index map: N)
MySQL 在获取数据时发现在没有索引可用,但当获取部分先前表字段值时发现可以采用当前表某些索引来获取数据。index map展示的是一个掩码值,如 index map:0x19,对应二进制值为 11001,表示当前表索引编号为 1、4 和 5 号索引可能被用来获取数据,索引编号通过 SHOW INDEX 语句获得。
1 2 3 4 5 6 7 8 9
mysql root@localhost:employees> explain select * from employees e,dept_emp d where e.emp_no > d.emp_no; +----+-------------+-------+------------+------+---------------+--------+---------+--------+--------+----------+------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+--------+---------+--------+--------+----------+------------------------------------------------+ | 1 | SIMPLE | d | <null> | ALL | PRIMARY | <null> | <null> | <null> | 331143 | 100.0 | <null> | | 1 | SIMPLE | e | <null> | ALL | PRIMARY | <null> | <null> | <null> | 299512 | 33.33 | Range checked for each record (index map: 0x1) | +----+-------------+-------+------------+------+---------------+--------+---------+--------+--------+----------+------------------------------------------------+ 2 rows in set Time: 0.038s
Select tables optimized away
MySQL 优化器能够确定以下两点:
最多只有一行记录被返回;
为了获取这一行数据,有一定的结果集需要获取。
当语句在优化器阶段过程中可以获取查询结果(如获取行数,只需要读取相应索引数据),而无需再返回表中查询数据,可能会出现 Select tables optimized away。例如针对 MyISAM 引擎的表,使用 select count(*) 获取表的总行数,而且又没有 where 子句或者条件总是为真,也没有 GROUP BY 子句时,其实就包含了以上的条件且隐式含有 GROUP BY 分组的效果。