内容简介:本文主要通过一些实例介绍如何使用 mysql 中的 explain 关键字分析查询语句,好让我们的查询语句写的更踏实,也让我们养成用 explain 分析的习惯,养成查询语句的写法习惯。在 mysql 里,mysql 使用
本文主要通过一些实例介绍如何使用 mysql 中的 explain 关键字分析查询语句,好让我们的查询语句写的更踏实,也让我们养成用 explain 分析的习惯,养成查询语句的写法习惯。
概念介绍
在 mysql 里, explain
是执行计划的意思,即可以通过该命令看出 mysql 是如何执行该条 sql 的,可以通过分析索引,表结构等方面来优化你的慢查询语句。
mysql 使用 explain + sql 语句
来查看执行计划,执行结果有十个字段,具体描述如下:
字段 | 描述 |
---|---|
id |
id相同,执行顺序由上至下;id不同,id的序号会递增,id值越大优先级越高,越先被执行 |
select_type |
主要是用于区别普通查询、联合查询、子查询等的复杂查询 |
table |
当前执行的表 |
type |
访问类型 |
possible_keys |
可能使用的索引 |
key |
实际使用的索引 |
key_len |
使用的索引的长度 |
ref |
显示索引的哪一列被使用了 |
rows |
查询过程中可能扫描的行数 |
Extra |
解析查询的额外信息,通常会显示是否使用了索引,是否需要排序,是否会用到临时表等 |
其中 type
字段可选值如下,性能从低到高排列:
type | 说明 |
---|---|
ALL |
全数据表扫描 |
index |
全索引表扫描 |
RANGE |
对索引列进行范围查找 |
INDEX_MERGE |
合并索引,使用多个单列索引搜索 |
REF |
根据索引查找一个或多个值 |
EQ_REF |
搜索时使用primary key 或 unique类型 |
CONST |
常量,表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次 |
SYSTEM |
系统,表仅有一行(=系统表)。这是const联接类型的一个特例 |
OK,概念匆匆介绍之后,结合自己的分析习惯,下面会通过实例聚焦 type
、 key
、 rows
、 Extra
这几个字段,来介绍如何分析我们的查询语句。
实例分析
数据初始化
新建测试表,插入 10 w 数据:
CREATE TABLE `test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `a` int(11) NOT NULL, `b` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; -- 批量插入 10w 数据 -- DROP PROCEDURE IF EXISTS batchInsert DELIMITER $ CREATE PROCEDURE batchInsert () BEGIN DECLARE i INT DEFAULT 1; START TRANSACTION; WHILE i<=100000 DO INSERT INTO test (a,b) VALUES (i,i); SET i=i+1; END WHILE; COMMIT; END $ CALL batchInsert ();
全表查询
目前默认只有一个主键索引,我们分析下全表查询:
mysql> explain select * from test;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
test |
ALL |
NULL |
NULL |
NULL |
NULL |
100333 |
NULL |
其中 type 值为 ALL,表示全表扫描了,我们看到 rows 这个字段显示有 100332 条,实际上我们一共才 10w 条数据,说明这个字段只是 mysql 的一个预估,不总是准确的。这个 test 表一次真实的查询时间为:2.708000s,可见这种全表扫描的效率非常低,是需要被优化的。
索引查询
接下来我们分别给字段 a 和 b 添加普通索引。
mysql> alter table test add index idx_a(a); mysql> alter table test add index idx_b(b);
看下下面这条 sql:
mysql> explain select * from test where a > 10000;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
test |
ALL |
idx_a |
NULL |
NULL |
NULL |
100333 |
Using where |
我们发现 type
竟然不是 index, 刚刚不是给字段 a 添加索引了么?还有 possible_keys
也显示了有 a_index,但是 key
显示 null,表示实际上不会使用任何索引,这是为什么呢?
这是因为 select * 的话还需要回到主键索引上查找 b 字段,这个过程叫 回表
。
这条语句会从索引中查出 9w 条数据,也就是说这 9w 条数据都需要 回表
操作,全表扫描都才 10w 条数据,所以在 mysql 最后的决策是还不如直接全表扫描得了,至少还免去了回表过程了。
当然,最后决策是否用索引不是固定的,mysql 会比较各种查询的代价,我们把上面的 sql 中 where 条件再稍微改造一下。
mysql> explain select * from test where a > 90000;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
test |
range |
idx_a |
idx_a |
4 |
NULL |
9999 |
Using index condition |
再看这次 type
为 range 了, key
为 a_index,表示使用了 a 索引,如我们所愿了。这是因为满足这次索引中查出只有 10000 条数据,mysql 认为 10000 条数据就算回表也要比全表扫描的代价低,因而决定查索引。
上面两条查询说明 mysql 会比较 索引 + 回表
和 直接全表扫描
的查询性能,选择其中更好的作为最后的查询方式,这就是 mysql 优化器的作用了。
还有一点就是这次 Extra
字段中值为 Using index condition,这是指条件过滤的时候用到了索引,但因为是 select * ,所以还是需要回表,再看下面这个语句。
mysql> explain select a from test where a > 90000;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
test |
range |
idx_a |
idx_a |
4 |
NULL |
9999 |
Using where; Using index |
注意这次 Extra
的值为 Using where; Using index,表示查询用到了索引,且要查询的字段在索引中就能拿到,所以不需要回表,显然这种效率比上面的要高,这也是日常开发中不建议写 select * 的原因,尽量只查询业务所需的字段。
排序查询
再来看一个带 排序 的查询。
mysql> explain select a from test where a > 90000 order by b;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
test |
range |
idx_a |
idx_a |
4 |
NULL |
9999 |
Using index condition; Using filesort |
我们知道索引本来就是有序带,但这个 Extra
中返回了一个 Using filesort,说明无法利用索引完成排序,需要从内存或磁盘进行排序,具体哪种排序 explain 是没有体现的。
总之,这种情况也是需要优化的,尽量能利用索引的有序性,比如下面:
mysql> explain select a from test where a > 90000 order by a;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
test |
range |
idx_a |
idx_a |
4 |
NULL |
9999 |
Using where; Using index |
这次 Extra
值有 Using index 了,表示使用上了索引。
复合索引
我们再创建一个复合索引看看。
mysql> alter table test add index idx_a_b(a,b);
看下之前的查询 mysql> explain select * from test where a > 10000;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 |
SIMPLE |
t |
range |
idx a,idx a_b |
idx a b |
4 |
NULL |
50166 |
Using where; Using index |
这条 sql 刚刚在没有创建复合索引的时候,是走的全表扫描,现在看 Extra
有 Using index,说明利用了覆盖索引,同样也免去了回表过程,即在 idx a
b 索引上就能找出要查询的字段。
总结
本文通过几个实例介绍了如何使用 explain
来分析一条 sql 的查询计划,例子都很简单,旨在能通俗易懂的说明白一些常见的查询问题,也让我们能养成良好的查询习惯。
参考
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_rows https://blog.csdn.net/poxiaonie/article/details/77757471 https://www.cnblogs.com/tufujie/p/9413852.html https://www.xttblog.com/?p=4225
以上所述就是小编给大家介绍的《explain 让你的 sql 写的更踏实》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
拆掉互联网那堵墙
庄良基 / 经济日报出版社 / 2014-6 / 25.80
都在说道互联网、说道电子商务、说道移动APP、说道微信、说道互联网金融......我们该如何认识互联网?中小微企业该如何借力互联网?互联网很神秘吗?很高深莫测吗? 其实互联网并没有什么神秘的,也没有什么高深莫测的!互联网无非是人类发明的工具而已,既然是工具,我们就一定可以驾驭和使用它。既然可以双重使用,就理当让所有有人都容易掌握并轻松驾驭。 互联网离我们很远吗?互联网界的成功故事都是那......一起来看看 《拆掉互联网那堵墙》 这本书的介绍吧!