Explain简介Explain关键字是Mysql中sql优化常用的“关键字”。通常使用Explain来“不执行sql查看sql的执行计划”,从而快速找出sql的问题所在。在讲解Explain之前,先创建需要的“用户表user,角色表role,用户角色关系表role_user”作为测试表://usertableDROPTABLEIFEXISTS`user`;CREATETABLE`user`(`id`int(11)NOTNULL,`name`varchar(25)DEFAULTNULL,`age`int(11)NOTNULLDEFAULT0,`update_time`datetimeDEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;INSERTINTO`user`(`id`,`name`,`age`,`update_time`)VALUES(1,'张三',23,'2020-12-2215:27:18'),(2,'李四',24,'2020-06-2115:27:18'),(3,'王舞',25,'2020-07-2015:27:18');DROPTABLEIFEXISTS`role`;CREATETABLE`role`(`id`int(11)NOTNULLAUTO_INCREMENT,`name`varchar(10)DEFAULTNULL,PRIMARYKEY(`id`),KEY`index_name`(`name`))ENGINE=InnoDBDEFAULTCHARSET=utf8;INSERTINTO`role`(`id`,`name`)VALUES(1,'产品经理'),(2,'技术经理'),(3,'项目总监');DROPTABLEIFEXISTS`role_user`;CREATETABLE`role_user`(`id`int(11)NOTNULL,`role_id`int(11)NOTNULL,`user_id`int(11)NOTNULL,PRIMARYKEY(`id`),KEY`index_role_user_id`(`role_id`,`user_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;INSERTINTO`role_user`(`id`,`role_id`,`user_id`)VALUES(1,2,1),(2,1,2),(3,3,3);我们先执行一条sql:explainselect*fromuserwhereid=2;,执行后可以看到执行结果如下:可以看到有12个字段,都有对应的值。这是explain的执行计划。如果你能看懂这个执行计划,你离精通sql优化也就不远了。下面详细介绍一下这12个字段分别是什么意思。id字段id表示执行select查询语句的序号,是sql执行顺序的标识,SQL按照id从大到小执行,相同id为一组,从上到下执行。什么意思呢?比如执行这条sql:explainselect*fromuserwhereidin(selectuser_idfromrole_user);+----+------------+-----------+------------+--------+------------+-------------------+--------+------+------+----------+----------------------------------------------------------------------------+|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|+----+------------+------------+-----------+--------+----------------+--------------------+-------+-----+------+--------+------------------------------------------------------------------------------+|1|SIMPLE|user|NULL|ALL|PRIMARY|NULL|NULL|NULL|3|100.00|NULL||1|SIMPLE|role_user|NULL|index|NULL|index_role_user_id|8|NULL|3|33.33|Usingwhere;Usingindex;FirstMatch(user);Usingjoinbuffer(BlockNestedLoop)|+----+------------+----------+------------+--------+------------+-------------------+--------+-----+-----+---------+------------------------------------------------------------------------------+都显示了idsare一样,也就是说sql的执行是从上到下执行的。第一条记录对应user表,然后第二条记录对应role_user表。这是同一个id。如果id不同,比如执行下面的sql:explainselect(select1fromuserlimit1)fromrole;:+----+------------+-------+-------------+--------+----------------+-----------+---------+------+------+--------+------------+|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|+----+------------+--------+------------+--------+----------------+------------+--------+--------+------+--------+------------+|1|PRIMARY|role|NULL|index|NULL|index_name|33|NULL|3|100.00|Usingindex||2|SUBQUERY|user|NULL|index|NULL|PRIMARY|4|NULL|3|100.00|Usingindex|+----+------------+--------+------------+--------+--------------+------------+--------+------+------+---------+------------+你会看到有两条记录,两条记录的id会不一样,id越大,前面执行,可以看到执行了id=2的user表,也就是子查询部分,最后执行的是最外层。”结论:“这就是id标识的sql的执行顺序。一般复杂查询会有多条记录,简单查询只有一条记录。复杂查询中,相同id为一组,执行顺序为从上到下。id大的先执行;在Mysql8中,子查询将被优化,所以有时即使是复杂的查询也只有一条记录。select_type字段select_type表示查询的类型,即对应的是简单查询还是复杂查询。如果是复杂查询,还包括:“简单子查询,from子句的子查询,联合查询”。我们分别来看一下select_type中的所有查询类型。simplesimple表示没有任何复杂查询的简单查询。在PRIMARY复杂查询中,“最外层select语句的查询类型为PRIMARY”,例如执行如下sql:explainselect*fromrolewhereid=(selectidfromrole_userwhererole_id=(selectidfromuserwhereid=2);最外层select,即select*fromrolewhereid=?将被标记为PRIMARY类型。SUBQUERY在“selectorwhere”子查询中会被表示为一个SUBQUERY类型。比如上一句执行的SQL中有两个子查询为SUBQUERY。DERIVED"DERIVED表示派生表或派生表,在from包含的子查询中将表示为DERIVED类型。"Mysql会递归执行这些子查询,并将结果放在一个临时表中。执行sql:explainselect*from(selectnamefromuserunionselectnamefromrole)awherea.name='张三';在Mysql5.7以上版本进行了优化,增加了derived_merge(派生合并),可以加快查询效率。当UNION出现“在UNION查询语句中,第二个select查询语句会表示为UNION”:UNIONRESULT“UNION查询语句的结果被标记为UNIONRESULT”,如上面执行的sql:explainselect*from(selectnamefromuserunionselectnamefromrole)awherea.name='张三';从第四行记录中的表字段可以看出,第四行记录来自于第二行和第三行
