103 透彻研究通过explain命令得到的SQL执行计划(4)
现在我们来看一个稍微复杂一点的SQL语句
EXPLAIN SELECT * FROM t1 WHERE x1 IN (SELECT x1 FROM t2 WHERE x1 = 'xxx' UNION SELECT x1 FROM t1 WHERE x1 = 'xxx');
这个SQL语句就稍微有点复杂了,因为他有一个外层查询,还有一个内层子查询,子查询里还有两个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,因为在执行子查询里两个结果集的合并以及去重。
现在再来看一个更加复杂一点的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条件来进行过滤,看看他的执行计划:
+----+-------------+------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| 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,意思就是说,针对子查询执行后的结果集会物化为一个内部临时表,然后外层查询是针对这个临时的物化表执行的。
大家可以看到,他这里执行分组聚合的时候,是使用的index_x1这个索引来进行的,type是index,意思就是直接扫描偶了index_x1这个索引树的所有叶子节点,把x1相同值的个数都统计出来就可以了。
然后外层查询是第一个执行计划,select_type是PRIMARY,针对的table是 'derived2',就是一个子查询结果集物化形成的临时表,他是直接针对这个物化临时表进行了全表扫描根据where条件进行筛选的。