mysql分析表关键字_SQL调优利器——explain关键字详解(MySQL)

前言

有时候,我们写好SQL后发现执行查询的时间超过了预期,但自己已经有根据表的已有索引去写SQL语句,这个时候就要考虑是否是在查询的过程中出现了索引失效的问题。那么我们可以怎么样去验证SQL在执行过程中是否有使用到索引呢?数据库给我们提供了explain关键字去查看sql的执行过程。

本篇文章将介绍explain关键字的用法和各个参数的含义,以期对该函数不了解的开发人员能够快速掌握SQL分析的技能。

本篇文章将以department和employee两张表(具体见后面的表结构参考)为例,进行文章的讲解,其中employee的name和age做了组合索引 。

语法

explain 要分析的SQL语句

6c8195466260

image.png

以上图为例,当我们使用explain来分析select * from employee这条句子后发现,出现了id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra共十个字段。那么这些字段分别是什么意思呢?我们可以通过这些字段的值来判断当前索引是否失效呢?下面,将对上述问题一一进行解答。

(一)explain字段含义解析

1. id

id表示执行select子句或者操作表的顺序

id相同时,从上到下依次执行

id不同时,根据id从大到小依次执行。(如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行)

6c8195466260

image.png

以上图为例,使用explain关键字查看sql执行过程后发现,会先执行id为2的子查询语句,再分别查询emp和dep两张表。至于为什么有这样的先后之分,是因为sql执行查询的时候会优先执行子查询语句的内容。

2. select_type

表示每个查询项的查询类型

类型

作用

SIMPLE

简单SELECT,不使用UNION或子查询等

PRIMARY

查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY

UNION

UNION中的第二个或后面的SELECT语句

DEPENDENT UNION

UNION中的第二个或后面的SELECT语句,取决于外面的查询

UNION RESULT

UNION中的第二个或后面的SELECT语句,取决于外面的查询

SUBQUERY

子查询中的第一个SELECT

DERIVED

派生表的SELECT, FROM子句的子查询

mysql> explain select * from department where id=(select id from employee where name='tony') union select * from department where id=(select id from employee where name='niky');

+------+---------------+-----------+-------+--------------+----------+---------+-------+-------+-------------+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+------+---------------+-----------+-------+--------------+----------+---------+-------+-------+-------------+

| 1 | PRIMARY | department | const | PRIMARY | PRIMARY | 4 | const | 1 | |

| 2 | SUBQUERY | employee | ALL | NULL | NULL | NULL | NULL | 8 | Using where |

| 3 | UNION | department | const | PRIMARY | PRIMARY | 4 | const | 1 | |

| 4 | SUBQUERY | employee | ALL | NULL | NULL | NULL | NULL | 8 | Using where |

| NULL | UNION RESULT | | ALL | NULL | NULL | NULL | NULL | NULL | |

+------+---------------+-----------+-------+--------------+----------+---------+-------+-------+-------------+

5 rows in set (0.08 sec)

以上面的例子,我们基本上可以看出常见的几种查询类型是在什么情况下使用的。

3. table

显示这一行的数据是关于哪张表的,有时是真实的表名字,有时也可能是以下几种结果

: 指id为M,N行结果的并集

: 该行是指id值为n的行的派生表结果。派生表可能来自例如from子句中的子查询。

: 该行是指id值为n的行的物化子查询的结果。

4. type(重要参数)

连接使用了哪种类别,有无使用索引,常用的类型有:system, const, eq_ref, ref, range, index, ALL(从左到右,性能越来越差)

类型

说明

all(Full Table Scan)

没有用到索引,MySQL将遍历全表以找到匹配的行

index(Full Index Scan)

index与ALL区别为index类型只遍历索引树

range

只检索给定范围的行,使用一个索引来选择行

ref

表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

eq_ref

类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

const

该表最多具有一个匹配行,该行在查询开始时读取。

system

该表只有一行(=系统表)。这是[const]联接类型的特例 。

一般来说,sql的级别能够达到eq_ref~index的话,都算是性能尚可的查询。

5. possible_keys

表示SQL能够使用哪些索引在表中查询数据,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用。也就是说,这个字段只是列出了可能使用到的索引,当出现理论上有使用索引,实际上没有的情况,很大可能就是出现了索引失效的问题了。

6c8195466260

image.png

6. key(重要)

key列显示数据库实际决定使用的键(索引)

如果实际执行查询过程中,没有使用索引,此处的值为NULL。

使用的索引的长度。在不损失精确性的情况下,长度越短越好

6c8195466260

image.png

7.ref

表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

这里要注意和type中的ref属性作区分,这里的ref是指作为匹配条件的值,而后者是指查询的一种类型。

6c8195466260

image.png

如上图,ref对应的值为const,说明作为匹配条件的“niky”是一个常量。

8. rows

表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数。

6c8195466260

image.png

这里表示需要扫描读取8行数据

9.Extra(重要)

该列包含MySQL解决查询的详细信息,有以下几种情况

Using where

使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题

6c8195466260

image.png

Uing index

列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤

6c8195466260

image.png

Using join buffer

改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。

Impossible where

这个值强调了where语句会导致没有符合条件的行。

6c8195466260

image.png

Using temporary

表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询。

Using filesort

MySQL中无法利用索引完成的排序操作称为“文件排序”

6c8195466260

此时,已有的索引无法满足sql需要

当出现Using temporary和Using filesort的时候,说明这条sql的效率比较低,这个时候就需要优化一下sql或者索引结构了。

(二)使用explain的综合分析小案例

SQL:select emp.age,dep.d_name from employee emp left join department dep on emp.dep_id=dep.id where emp.name='niky' order by dep.id ;

通过explain我们可以看到id列都为1,所以执行顺序将从上到下依次执行;没有使用子查询或者其他复杂的连接,所以此处的select_type为simple;查询使用的连接类别为ref和eq_ref,说明使用到了索引,查询的性能尚可;possible_key和key保持一致,没有出现索引失效的情况;ref列的值说明了两段查询中使用到了匹配值分别为常量和emp表的dep_id字段;Extra列中显示该sql语句中使用到了临时表和文件内排序,原因是两表关联后根据dep表的id字段排序,没有使用到索引。

这里的话,我们可以改用排序条件来优化sql。

6c8195466260

优化前

6c8195466260

优化后

相关建表sql参考

-- ----------------------------

-- Table structure for department

-- ----------------------------

DROP TABLE IF EXISTS `department`;

CREATE TABLE `department` (

`id` int(11) NOT NULL,

`d_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,

PRIMARY KEY (`id`) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Compact;

-- ----------------------------

-- Records of department

-- ----------------------------

INSERT INTO `department` VALUES (1, 'HR');

INSERT INTO `department` VALUES (2, 'FI');

INSERT INTO `department` VALUES (3, 'RD');

INSERT INTO `department` VALUES (4, 'SD');

INSERT INTO `department` VALUES (5, 'MAR');

-- ----------------------------

-- Table structure for employee

-- ----------------------------

DROP TABLE IF EXISTS `employee`;

CREATE TABLE `employee` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '员工id',

`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '员工姓名',

`dep_id` int(11) NULL DEFAULT NULL COMMENT '所属部门id',

PRIMARY KEY (`id`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Compact;

-- ----------------------------

-- Records of employee

-- ----------------------------

INSERT INTO `employee` VALUES (1, 'amy', 1);

INSERT INTO `employee` VALUES (2, 'tony', 1);

INSERT INTO `employee` VALUES (3, 'jack', 4);

INSERT INTO `employee` VALUES (4, 'jony', 2);

INSERT INTO `employee` VALUES (5, 'niky', 3);

INSERT INTO `employee` VALUES (6, 'tini', 5);

INSERT INTO `employee` VALUES (7, 'itern', 10);

INSERT INTO `employee` VALUES (8, 'bob', 5);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值