MySQL 优化:Explain 执行计划详解

e59e6d2000fae6f807dc2c1674a908d2.png

昨天中午在食堂,和部门的技术大牛们坐在一桌吃饭,作为一个卑微技术渣仔默默的吃着饭,听大佬们高谈阔论,研究各种高端技术,我TM也想说话可实在插不上嘴。

聊着聊着突然说到他上午面试了一个工作6年的程序员,表情挺复杂,他说:我看他简历写着熟悉SQL语句调优,就问了下 Explain 执行计划怎么看?结果这老哥一问三不知,工作6年这么基础的东西都不了解!

感受到了大佬的王之鄙视,回到工位我就开始默默写这个,哎~  我TM也不太懂 Explain ,老哥你这是针对我啊!哭唧唧~96623da8b9ea601f14090b55072efbed.png

Explain有什么用

ExplainSQL语句一起使用时,MySQL 会显示来自优化器关于SQL执行的信息。也就是说,MySQL解释了它将如何处理该语句,包括如何连接表以及什么顺序连接表等。

  • 表的加载顺序

  • sql 的查询类型

  • 可能用到哪些索引,哪些索引又被实际使用

  • 表与表之间的引用关系

  • 一个表中有多少行被优化器查询 .....

Explain有哪些信息

Explain 执行计划包含字段信息如下:分别是 idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra 12个字段。c446fd648063d6a371ad59809692d2df.png下边我们会结合具体的SQL示例,详细的解读每个字段以及每个字段中不同参数的含义,以下所有示例数据库版本为 MySQL.5.7.17

mysql> select version() from dual;
+------------+
| version()  |
+------------+
| 5.7.17-log |
+------------+

我们创建三张表 onetwothree,表之间的关系 one.two_id = two.two_id AND two.three_id = three.three_id

Explain执行计划详解

一、id

id: :表示查询中执行select子句或者操作表的顺序,id的值越大,代表优先级越高,越先执行id大致会出现 3种情况:

1、id相同

看到三条记录的id都相同,可以理解成这三个表为一组,具有同样的优先级,执行顺序由上而下,具体顺序由优化器决定。

mysql> EXPLAIN SELECT * FROM one o,two t, three r WHERE o.two_id = t.two_id AND t.three_id = r.three_id;
+----+-------------+-------+------------+--------+---------------+---------+---------+----------------------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref                  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+--------+---------------+---------+---------+----------------------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | o     | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                 |    2 |      100 | NULL                                               |
|  1 | SIMPLE      | t     | NULL       | ALL    | PRIMARY       | NULL    | NULL    | NULL                 |    2 |       50 | Using where; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | r     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | xin-slave.t.three_id |    1 |      100 | NULL                                               |
+----+-------------+-------+------------+--------+---------------+---------+---------+----------------------+------+----------+----------------------------------------------------+
2、id不同

如果我们的 SQL 中存在子查询,那么 id的序号会递增,id值越大优先级越高,越先被执行 。当三个表依次嵌套,发现最里层的子查询 id最大,最先执行。

mysql> EXPLAIN select * from one o where o.two_id = (select t.two_id from two t where t.three_id = (select r.three_id  from three r where r.three_name='我是第三表2'));
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | PRIMARY     | o     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |       50 | Using where |
|  2 | SUBQUERY    | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |       50 | Using where |
|  3 | SUBQUERY    | r     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |       50 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
3、以上两种同时存在

将上边的 SQL 稍微修改一下,增加一个子查询,发现 id的以上两种同时存在。相同id划分为一组,这样就有三个组,同组的从上往下顺序执行,不同组 id值越大,优先级越高,越先执行。

mysql>  EXPLAIN select * from one o where o.two_id = (select t.two_id from two t where t.three_id = (select r.three_id  from three r where r.three_name='我是第三表2')) AND o.one_id in(select one_id from one where o.one_name="我是第一表2");
+----+-------------+-------+------------+--------+---------------+---------+---------+--------------------+------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref                | rows | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+--------------------+------+----------+-------------+
|  1 | PRIMARY     | o     | NULL       | ALL    | PRIMARY       | NULL    | NULL    | NULL               |    2 |       50 | Using where |
|  1 | PRIMARY     | one   | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | xin-slave.o.one_id |    1 |      100 | Using index |
|  2 | SUBQUERY    | t     | NULL       | ALL    | NULL          | NULL    | NULL    | NULL               |    2 |       50 | Using where |
|  3 | SUBQUERY    | r     | NULL       | ALL    | NULL          | NULL    | NULL    | NULL               |    2 |       50 | Using where |
+----+-------------+-------+------------+--------+---------------+---------+---------+--------------------+------+----------+-------------+

二、select_type

select_type:表示 select 查询的类型,主要是用于区分各种复杂的查询,例如:普通查询联合查询子查询等。

1、SIMPLE

SIMPLE:表示最简单的 select 查询语句,也就是在查询中不包含子查询或者 union交并差集等操作。

2、PRIMARY

PRIMARY:当查询语句中包含任何复杂的子部分,最外层查询则被标记为PRIMARY

3、SUBQUERY

SUBQUERY:当 selectwhere 列表中包含了子查询,该子查询被标记为:SUBQUERY

4、DERIVED

DERIVED:表示包含在from子句中的子查询的select,在我们的 from 列表中包含的子查询会被标记为derived

5、UNION

UNION:如果union后边又出现的select 语句,则会被标记为union;若 union 包含在 from 子句的子查询中,外层 select 将被标记为 derived

6、UNION RESULT

UNION RESULT:代表从union的临时表中读取数据,而table列的<union1,4>表示用第一个和第四个select的结果进行union操作。

mysql> EXPLAIN select t.two_name, ( select one.one_id from one) o from (select two_id,two_name from two where two_name ='') t  union (select r.three_name,r.three_id from three r);+------+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+
| id   | select_type  | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra           |
+------+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+
|    1 | PRIMARY      | two        | NULL       | ALL   | NULL          | NULL    | NULL    | NULL |    2 |       50 | Using where     |
|    2 | SUBQUERY     | one        | NULL       | index | NULL          | PRIMARY | 4       | NULL |    2 |      100 | Using index     |
|    4 | UNION        | r          | NULL       | ALL   | NULL          | NULL    | NULL    | NULL |    2 |      100 | NULL            |
| NULL | UNION RESULT | <union1,4> | NULL       | ALL   | NULL          | NULL    | NULL    | NULL | NULL | NULL     | Using temporary |
+------+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+

三、table

查询的表名,并不一定是真实存在的表,有别名显示别名,也可能为临时表,例如上边的DERIVED<union1,4>等。

四、partitions

查询时匹配到的分区信息,对于非分区表值为NULL,当查询的是分区表时,partitions显示分区表命中的分区情况。

+----+-------------+----------------+---------------------------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table          | partitions                      | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+----------------+---------------------------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | one            | p201801,p201802,p201803,p300012 | index | NULL          | PRIMARY | 9       | NULL |    3 |      100 | Using index |
+----+-------------+----------------+---------------------------------+-------+---------------+---------+---------+------+------+----------+-------------+

五、type

type:查询使用了何种类型,它在 SQL优化中是一个非常重要的指标,以下性能从好到坏依次是:system  > const > eq_ref > ref  > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

1、system

system: 当表仅有一行记录时(系统表),数据量很少,往往不需要进行磁盘IO,速度非常快。

2、const

const:表示查询时命中 primary key 主键或者 unique 唯一索引,或者被连接的部分是一个常量(const)值。这类扫描效率极高,返回数据量少,速度非常快。

mysql> EXPLAIN SELECT * from three where three_id=1;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | three | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |      100 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
3、eq_ref

eq_ref:查询时命中主键primary key 或者 unique key索引, type 就是 eq_ref

mysql> EXPLAIN select o.one_name from one o ,two t where o.one_id = t.two_id ; 
+----+-------------+-------+------------+--------+---------------+----------+---------+--------------------+------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key      | key_len | ref                | rows | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+----------+---------+--------------------+------+----------+-------------+
|  1 | SIMPLE      | o     | NULL       | index  | PRIMARY       | idx_name | 768     | NULL               |    2 |      100 | Using index |
|  1 | SIMPLE      | t     | NULL       | eq_ref | PRIMARY       | PRIMARY  | 4       | xin-slave.o.one_id |    1 |      100 | Using index |
+----+-------------+-------+------------+--------+---------------+----------+---------+--------------------+------+----------+-------------+
4、ref

ref:区别于eq_refref表示使用非唯一性索引,会找到很多个符合条件的行。

mysql> select o.one_id from one o where o.one_name = "xin" ; 
+--------+
| one_id |
+--------+
|      1 |
|      3 |
+--------+``````sql
mysql> EXPLAIN select o.one_id from one o where o.one_name = "xin" ; 
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key      | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | o     | NULL       | ref  | idx_name      | idx_name | 768     | const |    1 |      100 | Using index |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
5、ref_or_null

ref_or_null:这种连接类型类似于 ref,区别在于 MySQL会额外搜索包含NULL值的行。

mysql> EXPLAIN select o.one_id from one o where o.one_name = "xin" OR o.one_name IS NULL; 
+----+-------------+-------+------------+-------------+---------------+----------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type        | possible_keys | key      | key_len | ref   | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------------+---------------+----------+---------+-------+------+----------+--------------------------+
|  1 | SIMPLE      | o     | NULL       | ref_or_null | idx_name      | idx_name | 768     | const |    3 |      100 | Using where; Using index |
+----+-------------+-------+------------+-------------+---------------+----------+---------+-------+------+----------+--------------------------+
6、index_merge

index_merge:使用了索引合并优化方法,查询使用了两个以上的索引。

下边示例中同时使用到主键one_id 和 字段one_nameidx_name 索引 。

mysql> EXPLAIN select * from one o where o.one_id >1 and o.one_name ='xin'; 
+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+------------------------------------------------+
| id | select_type | table | partitions | type        | possible_keys    | key              | key_len | ref  | rows | filtered | Extra                                          |
+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+------------------------------------------------+
|  1 | SIMPLE      | o     | NULL       | index_merge | PRIMARY,idx_name | idx_name,PRIMARY | 772,4   | NULL |    1 |      100 | Using intersect(idx_name,PRIMARY); Using where |
+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+------------------------------------------------+
7、unique_subquery

unique_subquery:替换下面的 IN子查询,子查询返回不重复的集合。

value IN (SELECT primary_key FROM single_table WHERE some_expr)
8、index_subquery

index_subquery:区别于unique_subquery,用于非唯一索引,可以返回重复值。

value IN (SELECT key_column FROM single_table WHERE some_expr)
9、range

range:使用索引选择行,仅检索给定范围内的行。简单点说就是针对一个有索引的字段,给定范围检索数据。在where语句中使用 bettween...and<><=in 等条件查询 type 都是 range

举个栗子:three表中three_id为唯一主键,user_id普通字段未建索引。

mysql> EXPLAIN SELECT * from three where three_id BETWEEN 2 AND 3;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | three | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    1 |      100 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

从结果中看到只有对设置了索引的字段,做范围检索 type 才是 range

mysql> EXPLAIN SELECT * from three where user_id BETWEEN 2 AND 3;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | three | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
10、index

indexIndexALL 其实都是读全表,区别在于index是遍历索引树读取,而ALL是从硬盘中读取。

下边示例:three_id 为主键,不带 where 条件全表查询 ,type结果为index

mysql> EXPLAIN SELECT three_id from three ;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | three | NULL       | index | NULL          | PRIMARY | 4       | NULL |    1 |      100 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
11、ALL

ALL:将遍历全表以找到匹配的行,性能最差。

mysql> EXPLAIN SELECT * from two ;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | two   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |      100 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

六、possible_keys

possible_keys:表示在MySQL中通过哪些索引,能让我们在表中找到想要的记录,一旦查询涉及到的某个字段上存在索引,则索引将被列出,但这个索引并不定一会是最终查询数据时所被用到的索引。具体请参考上边的例子。

七、key

key:区别于possible_keys,key是查询中实际使用到的索引,若没有使用索引,显示为NULL。具体请参考上边的例子。

typeindex_merge 时,可能会显示多个索引。

八、key_len

key_len:表示查询用到的索引长度(字节数),原则上长度越短越好 。

  • 单列索引,那么需要将整个索引长度算进去;

  • 多列索引,不是所有列都能用到,需要计算查询中实际用到的列。

注意:key_len只计算where条件中用到的索引长度,而排序和分组即便是用到了索引,也不会计算到key_len中。

九、ref

ref:常见的有:constfuncnull,字段名。

  • 当使用常量等值查询,显示const

  • 当关联查询时,会显示相应关联表的关联字段

  • 如果查询条件使用了表达式函数,或者条件列发生内部隐式转换,可能显示为func

  • 其他情况null

十、rows

rows:以表的统计信息和索引使用情况,估算要找到我们所需的记录,需要读取的行数。

这是评估SQL 性能的一个比较重要的数据,mysql需要扫描的行数,很直观的显示 SQL 性能的好坏,一般情况下 rows 值越小越好。

mysql> EXPLAIN SELECT * from three;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | three | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |      100 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

十一、filtered

filtered 这个是一个百分比的值,表里符合条件的记录数的百分比。简单点说,这个字段表示存储引擎返回的数据在经过过滤后,剩下满足条件的记录数量的比例。

MySQL.5.7版本以前想要显示filtered需要使用explain extended命令。MySQL.5.7后,默认explain直接显示partitionsfiltered的信息。

十二、Extra

Extra :不适合在其他列中显示的信息,Explain 中的很多额外的信息会在 Extra 字段显示。

1、Using index

Using index:我们在相应的 select 操作中使用了覆盖索引,通俗一点讲就是查询的列被索引覆盖,使用到覆盖索引查询速度会非常快,SQl优化中理想的状态。

什么又是覆盖索引?

一条 SQL只需要通过索引就可以返回,我们所需要查询的数据(一个或几个字段),而不必通过二级索引,查到主键之后再通过主键查询整行数据(select * )。

one_id表为主键

mysql> EXPLAIN SELECT one_id from one ;
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key        | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | one   | NULL       | index | NULL          | idx_two_id | 5       | NULL |    3 |      100 | Using index |
+----+-------------+-------+------------+-------+---------------+------------+---------+------+------+----------+-------------+

注意:想要使用到覆盖索引,我们在 select 时只取出需要的字段,不可select *,而且该字段建了索引。

mysql> EXPLAIN SELECT * from one ;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | one   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |      100 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
2、Using where

Using where:查询时未找到可用的索引,进而通过where条件过滤获取所需数据,但要注意的是并不是所有带where语句的查询都会显示Using where

下边示例create_time 并未用到索引,typeALL,即MySQL通过全表扫描后再按where条件筛选数据。

mysql> EXPLAIN SELECT one_name from one where create_time ='2020-05-18';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | one   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
3、Using temporary

Using temporary:表示查询后结果需要使用临时表来存储,一般在排序或者分组查询时用到。

mysql> EXPLAIN SELECT one_name from one where one_id in (1,2) group by one_name;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | one   | NULL       | range| NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using temporary; Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
4、Using filesort

Using filesort:表示无法利用索引完成的排序操作,也就是ORDER BY的字段没有索引,通常这样的SQL都是需要优化的。

mysql> EXPLAIN SELECT one_id from one  ORDER BY create_time;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | one   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |      100 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+

如果ORDER BY字段有索引就会用到覆盖索引,相比执行速度快很多。

mysql> EXPLAIN SELECT one_id from one  ORDER BY one_id;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | one   | NULL       | index | NULL          | PRIMARY | 4       | NULL |    3 |      100 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
5、Using join buffer

Using join buffer:在我们联表查询的时候,如果表的连接条件没有用到索引,需要有一个连接缓冲区来存储中间结果。

先看一下有索引的情况:连接条件 one_nametwo_name 都用到索引。

mysql> EXPLAIN SELECT one_name from one o,two t where o.one_name = t.two_name;
+----+-------------+-------+------------+-------+---------------+----------+---------+----------------------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref                  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+----------+---------+----------------------+------+----------+--------------------------+
|  1 | SIMPLE      | o     | NULL       | index | idx_name      | idx_name | 768     | NULL                 |    3 |      100 | Using where; Using index |
|  1 | SIMPLE      | t     | NULL       | ref   | idx_name      | idx_name | 768     | xin-slave.o.one_name |    1 |      100 | Using index              |
+----+-------------+-------+------------+-------+---------------+----------+---------+----------------------+------+----------+--------------------------+

接下来删掉 连接条件 one_nametwo_name 的字段索引。发现Extra 列变成 Using join buffertype均为全表扫描,这也是SQL优化中需要注意的地方。

mysql> EXPLAIN SELECT one_name from one o,two t where o.one_name = t.two_name;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |      100 | NULL                                               |
|  1 | SIMPLE      | o     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
6、Impossible where

Impossible where:表示在我们用不太正确的where语句,导致没有符合条件的行。

mysql> EXPLAIN SELECT one_name from one WHERE 1=2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra            |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
|  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | NULL     | Impossible WHERE |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
7、No tables used

No tables used:我们的查询语句中没有FROM子句,或者有 FROM DUAL子句。

mysql> EXPLAIN select now();
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | NULL     | No tables used |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+

Extra列的信息非常非常多,这里就不再一一列举了,详见 MySQL官方文档 :https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#jointype_index_merge75123c21c5ae32b1d834d94142a5d7cd.png

总结

上边只是简单介绍了下 Explain 执行计划各个列的含义,了解它不仅仅是要应付面试,在实际开发中也经常会用到。比如对慢SQL进行分析,如果连执行计划结果都不会看,那还谈什么SQL优化呢?


67d30631fa7ede83830e7a853e7651ba.jpeg

厉害了,3万字的MySQL精华总结 + 面试100问!

4b8f9dc757e5b16b32bebc35a2ecc220.jpeg

高质量SQL的30条建议!(后端必备)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/543929.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

顶级 Javaer 常用的 14 个类库

作者&#xff1a;小姐姐味道昨天下载下来Java16尝尝鲜。一看&#xff0c;好家伙&#xff0c;足足有176MB大。即使把jmc和jvisualvm给搞了出去&#xff0c;依然还是这么大&#xff0c;真的是让人震惊不已。但即使JDK足够庞大&#xff0c;它的功能也已经不够用了。我们需要借助于…

势头迅猛的儿童手表:恐陷下一个文曲星之地?

历史的节奏&#xff0c;就是不断重复此前发生过的事。虽然表现形态不一&#xff0c;但蕴藏的规律、趋势总是有着惊人的相似。在科技行业&#xff0c;同样如此——iPhone开启的智能手机时代走过的大兴—→平稳→下降态势&#xff0c;与PC的历程几乎是一样的。而在国内&#xff0…

scala 类中的对象是类_Scala中的类和对象

scala 类中的对象是类Scala中的课程 (Classes in Scala) A class is a blueprint for objects. It contains the definition of all the members of the class. There are two types of members of the class in Scala, 类是对象的蓝图。 它包含该类的所有成员的定义。 Scala中…

2022年终总结:不再用“拼命”来应对极度的不安全感

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;人生匆匆三十四余载&#xff0c;今天又到了辞旧迎新和 2022 年说再&#xff08;也不&#xff09;见的时刻了&#xff0c;所以…

Java 最常见的 200+ 面试题:面试必备

这份面试清单是从我 2015 年做了 TeamLeader 之后开始收集的&#xff0c;一方面是给公司招聘用&#xff0c;另一方面是想用它来挖掘在 Java 技术栈中&#xff0c;还有那些知识点是我不知道的&#xff0c;我想找到这些技术盲点&#xff0c;然后修复它&#xff0c;以此来提高自己…

vim中的jk为什么是上下_JK轮胎的完整形式是什么?

vim中的jk为什么是上下JK轮胎&#xff1a;Juggilal Kamlapat Ji轮胎 (JK Tyres: Juggilal Kamlapat Ji Tyres) JK Tyre and Industries is an abbreviation of Juggilal Kamlapat Ji Tyres & Industries Ltd. It is an Automobile Tyre, Tubes and Flaps manufacturing com…

【C语言】第二章 类型、运算符和表达式

为什么80%的码农都做不了架构师&#xff1f;>>> 变量和常量是程序处理的两种基本数据对象。 声明语句说明变量的名字及类型&#xff0c;也可以指定变量的初值。 运算符指定要进行的操作。 表达式则把变量与常量组合起来生成新的值。 对象的类型决定该对象可取值的集…

转: 加快Android编译速度

转&#xff1a; http://timeszoro.xyz/2015/11/25/%E5%8A%A0%E5%BF%ABandroid%E7%BC%96%E8%AF%91%E9%80%9F%E5%BA%A6/ 加快Android编译速度 发表于 2015-11-25 | 对于Android开发者而言&#xff0c;随着工程不断的壮大&#xff0c;Android项目的编译时间也逐渐变长&#xff…

ipv6寻址_什么是IPV4寻址?

ipv6寻址IPV4寻址简介 (Introduction to IPV4 Addressing ) Internet protocol version 4 in any network, is a standard protocol for assigning a logical address (IP address) to hosts. You are currently using the same protocol. This protocol is capable of providi…

最长递增子序列 子串_最长递增子序列

最长递增子序列 子串Description: 描述&#xff1a; This is one of the most popular dynamic programming problems often used as building block to solve other problems. 这是最流行的动态编程问题之一&#xff0c;通常用作解决其他问题的基础。 Problem statement: 问…

WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

原文:WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展一&#xff0e;前言 申明&#xff1a;WPF自定义控件与样式是一个系列文章&#xff0c;前后是有些关联的&#xff0c;但大多是按照由简到繁的顺序逐步发布的等&#xff0c;若有不明白的地方可以参考本…

bba70_BBA的完整形式是什么?

bba70BBA&#xff1a;工商管理学士 (BBA: Bachelor of Business Administration) BBA is an abbreviation of Bachelor of Business Administration also spelled as B.B.A. In the field of Business Administration, it is an undergraduate degree program. This is a degre…

Qt和纹理

2019独角兽企业重金招聘Python工程师标准>>> test 转载于:https://my.oschina.net/assange/blog/537631

计算机图形学图形旋转_计算机图形学翻译

计算机图形学图形旋转计算机图形学| 翻译 (Computer Graphics | Translations) Transformation techniques mean to modify the current shape or object in a particular manner. Changing of an object after creation, in terms of position or even size is known as trans…

AP 1532E register   Cisco 2504 AP注册WLC

客户的环境是&#xff1a;WLC是 2504 的AP的型号是 1532E的首先要是版本匹配&#xff0c;那么我们就要查一个兼容性列表&#xff0c;请看附件同时&#xff0c;我们要把WLC的版本升级到AIR-CT2500-K9-8-1-111-0.aes 这个版本&#xff1b;同时由于瘦AP 1532E的版本是 Cisco IOS S…

C#中IDisposable 回收非托管资源

C#中IDisposable 更多2014/9/7 来源&#xff1a;C#学习浏览量&#xff1a;4185学习标签&#xff1a; IDisposable本文导读&#xff1a;C#中IDisposable接口的主要用途是释放非托管资源。当不再使用托管对象时&#xff0c;垃圾回收器会自动释放分配给该对象的内存。但无法预测进…

css导航栏_使用CSS的导航栏

css导航栏CSS | 导航栏 (CSS | Navigation Bar) Developing websites is great but developing a user-friendly website is even greater. So how does one design a user-friendly website? What tools to use? Well, there are many tools to mention which are quite hel…

Java代理系列-静态代理

2019独角兽企业重金招聘Python工程师标准>>> 代理模式可以做很多事&#xff0c;像hibernate&#xff0c;spring都使用了代理模式。 spring的aop就是用代理做的。 本系列分为4章&#xff0c;静态代理&#xff0c;动态代理热身&#xff0c;动态代理&#xff0c;cglib代…

ajax的模式_AJAX的完整形式是什么?

ajax的模式AJAX&#xff1a;异步JavaScript和XML (AJAX: Asynchronous JavaScript and XML) AJAX is an abbreviation of Asynchronous JavaScript and XML. It is an organized collection of technologies and not of a single technology. Informing a collection of web De…

JAVA Opencv在图片上添加中文

问题描述&#xff1a; 将图片进行均值、中值、高斯滤波&#xff0c;高斯边缘检测&#xff0c;并在图片上添加中文文字。 一、算法思想 首先经过opencv的一系列操作&#xff0c;例如高斯模糊、均值模糊等操作后、用Imgcodecs.imwrite方法将图片写出到指定的位置。再利用java…