(1)回顾:
id:有一个SELECT子句就会对应一个id,如果有多个SELECT那么就会对应多个id。但往往一个SELECT语句涉及到了多个表,所以会对应多条执行计划,此时可能多条执行计划的id是一样的。
select_type:有SIMPLE,还有primary,subquery,首先,一般单表查询或者是多表查询,其实他们的select_type都是SIMPLE,如果是union语句的话,就会对应两个执行计划,第一条执行计划是针对t1表,select_type是primary,第二条执行计划是针对t2表的,select_type是union,这就是出现union语句的时候,他们就不一样了。
在使用union子句的时候,会有第三条执行计划,这个第三条执行计划意思是针对两个查询的结果依托一个临时表去重,这个第三条执行计划的select_type是union_result。
(2)稍微复杂的SQL语句:
EXPLAIN SELECT * FROM t1 WHERE x1 IN (SELECT x1 FROM t2 WHERE x1=’xxx’ UNION SELECT x1 FROM t1 WHERE x1=’xxx’ );
这个有一个外层查询,还有一个内层子查询,子查询里还有两个SELECT语句,进行union操作,来看看执行计划:
+----+--------------------+------------+------------+------+---------------+----------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+------------+------------+------+---------------+----------+---------+-------+------+----------+--------------------------+
| 1 | PRIMARY | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 3467 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | t2 | NULL | ref | index_x1 | index_x1 | 899 | const | 59 | 100.00 | Using where; Using index |
| 3 | DEPENDENT UNION | t1 | NULL | ref | index_x1 | index_x1 | 899 | const | 45 | 100.00 | Using where; Using index |
| NULL | UNION RESULT | <union2,3> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------------+------------+------------+------+---------------+----------+---------+-------+------+----------+--------------------------+
第一个执行计划就是针对t1表查询的外层循环,select_type就是primary,因为这里涉及到了子查询,所以外层查询的select_type一定是primary,
第二个执行计划是子查询里针对t2表的那个查询语句,他的select_type是DEPENDENT SUBQUERY,
第三个执行计划是子查询里针对t1表的另一个查询语句,select_type是DEPENDENT UNION,因为第三个执行计划是在执行union 后的查询,
第四个执行计划的select_type是UNION RESULT,因为在执行子查询里两个结果集的合并以及去重。
(3)更加复杂的SQL语句:
EXPLAIN SELECT FROM (SELECT x1, count() as cnt from t1 GROUP BY x1 ) as _t1 WHERE cnt > 10 ;
这个SQL语句就比较麻烦了,他是FROM 子句后面跟了一个子查询,在子查询里根据x1字段进行分组然后进行count 聚合操作,也就是统计出来 x1这个字段的每个值的个数,然后在外层则是针对这个内存查询的结果集进行查询通过where条件进行过滤,来看看执行计划: DERIVED 衍生,派生
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 3468 | 33.33 | Using where |
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| 2 | DERIVED | t1 | NULL | index | index_x1 | index_x1 | 899 | NULL | 3568 | 100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
上面的执行计划,我们先看第二条执行计划,子查询里的那个语句的执行计划,select_type是derived,意思是说,针对子查询执行后的结果集物化为一个内部临时表,然后外层查询针对这个临时的物化表执行的。<br />这里执行分组聚合的时候,是使用index_x1这个索引进行的,type是index,意思是直接扫描了 index_x1 这个索引树的所有叶子节点,把x1相同值的个数都统计出来就可以了。<br /> 然后外层查询是第一个执行计划,select_type是PRIMARY,针对的table是<derived2>,就是一个子查询结果集物化形成临时表,直接对这个物化表进行了全表扫描根据where条件筛选。
知识点:
1.primary:查询中包含复杂的子查询,最外层查询为primary
2.subquery:where中包含了子查询
3.derived:from中包含了子查询结果放入到物化表中
4.union:出现在union之后的第二个查询
5.union result:union之后的结果