专栏首页DBA随笔MySQL中explain中的结果字段介绍(三)

MySQL中explain中的结果字段介绍(三)

MySQL中explain中的结果字段介绍(三)

之前的文章中对于explain的数据结果中的字段已经进行了一部分介绍了,今天来说一说剩下的几个字段,为了防止忘记,先看看这个表结构:

mysql--dba_admin@127.0.0.1:yeyztest 21:13:04>>show create table test_explain\G
*************************** 1. row ***************************
       Table: test_explain
Create Table: CREATE TABLE `test_explain` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a_key_var` varchar(100) DEFAULT NULL,
  `b_key_int` int(11) DEFAULT NULL,
  `c_key_var` varchar(100) DEFAULT NULL,
  `d_key_var1` varchar(100) DEFAULT NULL,
  `d_key_var2` varchar(100) DEFAULT NULL,
  `d_key_var3` varchar(100) DEFAULT NULL,
  `e_normal_var` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_key_b` (`b_key_int`),
  KEY `idx_key_a` (`a_key_var`),
  KEY `idx_key_c` (`c_key_var`),
  KEY `idx_key_d` (`d_key_var1`,`d_key_var2`,`d_key_var3`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

先来看看最后几个字段是什么:

mysql:yeyztest 21:13:15>>explain select * from test_explain where id=2;
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table        | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test_explain | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

可以看到,分别是key_len,ref,rows,filtered以及extra这5个字段。下面我们介绍以下这5个字段的意思:

key_len

key_len表示当优化器制定某个列作为索引的时候,这个索引记录的最大长度,这里需要注意的是,这个最大长度的单位为字节,一般来讲,最大长度由以下三个因素决定:

1、如果该字段是固定长度的类型,例如char类型的,那么它实际占用存储空间的最大长度就是这个固定值。如果是varchar这种变长类型的,那么它的最大长度就是变长类型定义中的长度,比如对于varchar(20),采用utf8编码,最大长度就是20*3=60字节

2、如果索引列中可能包含null值,那么会额外占用1个字节

3、对于varchar这种变长字段,需要有额外的2个字节来保存长度

有了这三条规则,就能比较容易理解key_len的值了,例如上面的例子中,key_len的值是4,它的原因是int类型是固定长度,一个int是4个字节大小

再来看下面这个查询:

mysql:yeyztest 21:14:46>>explain select * from test_explain where a_key_var='a';
+----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table        | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test_explain | NULL       | ref  | idx_key_a     | idx_key_a | 303     | const |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

查询的字段是a_key_var,这个字段的类型是varchar(100),那么key_len真实的长度就是100*3+1+2,也就是303了。目前,我们这个字段a_key_var是可以为null值的,如果我们改成不能为null值,如下,可以看到key_len的值发生了变化,变成了302,这就说明了null值是占用了一个字节。

mysql:yeyztest 21:30:40>>alter table test_explain modify a_key_var varchar(100) not null default '';
Query OK, 9 rows affected (0.03 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql:yeyztest 22:15:09>>explain select * from test_explain where a_key_var='a';
+----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table        | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test_explain | NULL       | ref  | idx_key_a     | idx_key_a | 302     | const |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

ref

ref的值就是指在进行条件过滤的时候,与条件匹配的值是一个常数还是一个变量之类的,我们可以看到,上面的结果中,ref字段的值都是const,是因为我们使用常量a或者常量2和索引字段进行匹配,如果我们使用某个字段进行匹配,来看下面:

mysql:yeyztest 22:24:42>>explain select * from test_explain t1 inner join test2 t2 where t1.id=t2.id;
+----+-------------+-------+------------+--------+---------------+-----------+---------+----------------+------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key       | key_len | ref            | rows | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+-----------+---------+----------------+------+----------+-------------+
|  1 | SIMPLE      | t2    | NULL       | index  | PRIMARY       | idx_birth | 6       | NULL           |    1 |   100.00 | Using index |
|  1 | SIMPLE      | t1    | NULL       | eq_ref | PRIMARY       | PRIMARY   | 4       | yeyztest.t2.id |    1 |   100.00 | NULL        |
+----+-------------+-------+------------+--------+---------------+-----------+---------+----------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

这个例子中ref的值是yeyztest.t2.id,说明是t1的主键和这个id去做的匹配。

rows

rows代表的是执行计划预计扫描的索引记录行数。上面的例子中,我们可以看到,预计将会扫描的记录数为1条,但是需要注意的是,这个值是个预计值,而不能被看做真实值。

filter

这个值代表的是根据某个索引查询到记录数之后,大约有多少比例的记录匹配剩余的条件。也就是说,比如我们某个表的主键是id,过滤条件是id>4 and age<30,假设id>4的记录数预计为40条,也就是explain中的rows的记录为40,那么filter的意思就是在这40条记录里面,大概有多少比率的记录符合age<30.如下:

mysql:yeyztest 22:40:36>>explain select * from test_1 where id>=4 and age<30;
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test_1 | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |   40 |    33.33 | Using where |
+----+-------------+--------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

Extra

这个字段主要还是提供一些查询的额外信息,可能出现的情况比较多,这里列出来常用的一些即可,就不进行举例说明了。

Using where 表示Mysql将对storage engine提取的结果进行过滤,过滤条件字段无索引;

Using temporary 要解决查询,MySQL需要创建一个临时表来保存结果。如果查询包含不同列的GROUP BY和ORDER BY子句,则通常会发生这种情况

Using index 仅使用索引树中的信息从表中检索列信息,而不需要进行回表来读取实际行

Using index condition Using index condition 会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行;

Using filesort 当Query 中包含 ORDER BY 操作,而且无法利用索引完成排序操作的时候,MySQL Query Optimizer 不得不选择相应的排序算法来实现。数据较少时从内存排序,否则从磁盘排序

no matching ... && not exist

找不到匹配的记录。

Using join buffer

这种情况主要发生在join的连接查询中,将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数

本文分享自微信公众号 - DBA随笔(gh_acc2bbc0d447),作者:AsiaYe

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • MySQL中explain的结果​字段介绍

    昨天说完了执行计划的前四个字段,今天说说后面几个字段吧。我们看看explain的基本语法和输出内容:

    AsiaYe
  • Mysql中的Redo Log解析(一)

    Innodb是使用16k大小的数据页来管理存储空间的,数据页也是内存和磁盘交互的最小单位。我们知道事务提交后是先将修改过的数据页保存在内存中,然后再刷...

    AsiaYe
  • Linux命令之crontab

    Linux系统上面有很多计划性的工作,比如在某个时间点需要执行某个动作,在Linux中,一般使用crontab命令来实现控制计划任务,通过crontab 命令,...

    AsiaYe
  • 实例讲解redis字符串类型

    章鱼喵
  • Redis笔记(三):Redis常用命令

    启动 redis 客户端,打开终端并输入命令 redis-cli。该命令会连接本地的 redis 服务。

    朝雨忆轻尘
  • Redis的安装及基本使用1.Redis2.Redis安装3.redis常见配置4.redis数据操作5.redis发布订阅6.主从双备

    Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如 字符串(strings), ...

    意气相许的许
  • Redis 哈希(Hash)

    Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。

    只喝牛奶的杀手
  • redis操作命令总结

    先来介绍一下这篇文章的特点:最主要的是每条命令后面添加了详细的解释,以及英文单词的意思,便于大家理解,我也没想到有生之年我会这么多单词,哈哈哈哈.还有就是有的命...

    小闫同学啊
  • HashMap?ConcurrentHashMap?相信看完这篇没人能难住你!

    Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据。

    Java团长
  • 轻松理解 Java HashMap 和 ConcurrentHashMap

    Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据。

    烂猪皮

扫码关注云+社区

领取腾讯云代金券