前置知识:
[1] MySQL 执行计划

需要查看 SQL 语句的执行计划的时候,非常简单,只需要在 SQL 的前面加上 explain 关键字,然后执行即可。就会生成个执行计划。类似以下:
image.png

分析


上面这个执行计划的结果里面,只有 1 行数据,是因为这个 SQL 比较简单,只访问了 1 个 user 表。如果 SQL 比较复杂的话,执行计划结果里面会有多行数据。接下来分析每列的意义。

  • ID : 每个执行计划的唯一标识
  • SELECT_TYPE : 查询类型。 主要是代表了大 SQL 里面不同的 SELECT 代表一个什么角色。
  • TABLE : 对应查询的表
  • TYPE: 针对这个表的访问方式,有 const , ref , range , index, all 等, 决定了对某个表是如何查询数据的
  • POSSIBLE_KEYS : 当前执行计划可能会用到的索引。
  • KEY :当前执行计划实际使用的索引
  • KEY_LEN : 索引 key 的长度。
  • REF : 使用某个字段的索引进行等值匹配搜索的时候,跟索引列进行等值匹配的那个目标值的一些信息。
  • ROWS : 估计会访问多少条数据
  • Extra : 额外的信息

Extra : 包含一些重要的额外信息

  • Using filesort : 需要对数据进行排序的时候,没有找到能使用的索引,所以就只能用内存和磁盘的数据进行排序,导致产生了很多磁盘 IO, 效率很低。
  • Using tempporary : 在对结果进行排序的时候,使用了临时表,这个方式比 filesort 效率更低。
  • Using index : 使用了索引,这个方式效率非常高。

    除了这个几个重要的以外,还有很多额外信息。 更多可以看 [参考2] 。

简单多表关联分析


下面看一个多表关联的分析
image.png

在这个查询计划里面,关联查询了2个表,所以出现了2个结果。首先用全表扫描( ALL )的方式去查询 email 表,获取到2条数据,然后用 email 表嵌套循环查询 user 表,对 user 表也是全表扫描,扫描 user 表10条数据。Extra 信息里面有写到是使用了嵌套循环的方式。

注意,这里两个查询计划都的 id 都是1,因为查询计划的1个 select 对应1个 id 。说明这两个查询计划都属于同一个 select 。

子查询分析


image.png
在这个查询计划里面,也有2个结果,因为分别查询了2个表。两个计划的id是不一样的,因为有了2个 SELECT 。
主查询的id是1,子查询的id是2。

id=1 的查询类型是 PRIMARY ,意思是主查询。因为 where 条件里面有 sex 字段,并且由于 sex 字段建立了索引 index_sex ,所以可能用到的索引里面就包含了 index_sex 。但是 type 还是 ALL ,是因为经过估算,走索引的成本和全表扫描的成本差不多,所以最后选择了全表扫描。

id=2 的查询类型是子查询,针对的是 tb_email 表。是通过扫描 index_email 这个索引的全部叶子,并且不需要回表操作,所以类型是 index 。

UNION查询分析


image.png
联合查询的前两个执行计划和其他的没什么差别,比较简单,一个是进行了全表扫描,一个是扫描了 index_email 的所有叶子结点。由于是使用了 UNION 查询,所以最后会多出一个执行计划。是因为 UNION 默认是进行去重操作的,也就是查询出了2个表的结果后,还需要进行去重操作。多出来的执行计划就是去重的执行计划。如果使用的是 UNION ALL 关键字,则不会产生去重操作。

是一个临时的表名,扩展信息里面也写着是使用了 using temporary ,使用临时表的方式。操作类型是 UNION_RESULT 。去重操作是放在临时表里面进行的。

参考:
[1] MySQL explain 应用详解
[2] MySQL - EXPLAIN 详解