适用范围
介绍Mysql数据库中,sql执行计划里各个id部分的执行顺序。
概念描述
由于客户数据库推行国产化这一趋势,我最近也在看mysql的sql优化。优化大家都知道看懂sql执行计划对于优化的意义,然而我在学习中发现网上的一些说法是不准确的。例如,“id一样,按照顺序执行;id越大,执行的优先级就越高(如子查询)......”,于是这里结合自己最近的学习跟大家说说怎么看mysql的执行计划。
具体概念:
mysql执行计划中的id和select-type有关系,需要结合id值和被执行对象之间的关系,才能确定id的执行次序,分为如下情况:
1. 并列关系:如两个表之间做UNION操作,这两个对象是并列的关系,则id值小的先执行。id值相同,从上到下,依次执行。
2. 嵌套的关系:如存在子查询,首先启动的是id值小的,即对父对象先进行操作,在id值小的对象执行过程中,接着又启动了id值为大的子对象。
所以,最先执行完毕的是id值大者;最先执行的是id值小者。
3. 如果嵌套关系中,有多个子查询,且子查询间的关系是并列的,则执行顺序按照id序号进行,id值小的先执行。
4. 如果子查询在优化阶段被执行,则执行阶段不再执行,这中情况与id值表示的执行顺序没有关系。
相关知识普及:
id: 在⼀个⼤的查询语句中每个SELECT关键字都对应⼀个唯⼀的id
select-type: SELECT关键字对应的查询的类型
如下图所示:

派生表:<derivedN>形式,N表示产生派生表的查询的queryId
合并表:<unionN1,N2>形式,N2,N2表示参与union的查询的queryId
测试验证
下面通过测试来逐一说明一下:
(1)SIMPLE 简单查询,不包含union或者子查询,不做过多解释了
(2)PRIMARY 最外层的查询(并列关系示例)
mysql> EXPLAIN SELECT
-> o.emp_no,
-> o.birth_date,
-> t.first_name
-> FROM
-> ( SELECT a.emp_no, a.first_name FROM employees a WHERE a.first_name like 'G%'
-> UNION
-> SELECT a.emp_no, a.first_name FROM employees a WHERE a.gender = 'M' ) t
-> LEFT JOIN employees o ON o.emp_no = t.emp_no;

注释:按照网上的说法执行顺序是 4->3->2->1->1,这里其实是错误的。首先 t 是子查询,id=2和id=3是UNION的上下部分是并列关系,而id=4 是合并表其实就是<union2,3>查询的临时表也就是结果集 t。id=2又是id=1的派生表<derived2>,所以正确的执行顺序应该是2->3->4->1->1。
如果是mysql 8.0以上版本,可以查看explan analyze的执行计划:

注释:这个基本很接近oracle的执行计划了,遵守最右最上原则看即可。
(3)UNION 前面案例中id=2,id=3的部分,不再重复说了。
(4) UNION RESULT 前面案例中id=4的部分,不再重复说了。
(5)DERIVED 派生表,前面案例中id=1的部分,不再重复说了。
(6)DEPENDENT UNION 在union中的第二个或者之后的查询,并且外部查询依赖于union的结果(嵌套关系示例)
mysql> EXPLAIN SELECT
-> *
-> FROM employees
-> WHERE
-> emp_no IN
-> ( SELECT a.emp_no FROM employees a WHERE a.first_name like 'G%'
-> UNION
-> SELECT a.emp_no FROM employees a WHERE a.gender = 'M' );

注释:这里id=2,3,4的部分和前面类似,注意id=2的地方是DEPENDENT SUBQUERY,说明外部查询的结果依赖于union的结果属于嵌套关系,那么执行顺序是 2->3->4->1。当然外层查询的employees 是驱动表,被驱动表是id=4 返回的union的结果。
看下explain analyze的结果:

(7)subquery 在select或者where列表中包含的子查询
mysql> EXPLAIN SELECT
-> *
-> FROM
-> salaries s
-> where
-> s.salary > (SELECT avg( salary ) FROM salaries)
-> ;

explain analyze:的执行计划

注释:通常 SUBQUERY 的子查询只被执行一次,从explain analyze 执行计划中的提示可知。
知识总结
mysql执行计划中id的执行顺序,需要结合id值和被执行对象之间的关系才能确定。
1. 并列关系:如两个表之间做UNION操作,则id值小的先执行。id值相同,从上到下,依次执行。
2. 嵌套关系:如存在子查询,首先启动的是id值小的,即对父对象先进行操作,在id值小的对象执行过程中,接着又启动了id值为大的子对象。所以,最先执行完毕的是id值大者;最先执行的是id值小者。
参考文档
https://blog.csdn.net/fly2nn/article/details/61924721
MySQL执行计划中,ID值表明执行次序
MySQL 是怎样运行的:从根儿上理解 MySQL
MySQL执行计划中,ID值表明执行次序




