mysql sql优化 explain_SQL优化-使用explain分析SQL执行计划

有时候我们会遇到这样的事情:项目上线了,一切顺利,就等产品验收完毕回家睡觉了,但是产品突然来找你了:

产品:首页为什么加载这么慢

开发:数据量太大了,没办法

产品:不行,必须优化

开发:....

这种情况,很大概率是sql出现慢查询了,此时我们就需要把查询sql拉出来优化优化了,那我们就需要使用到本文要说的explain命令了。

本文目的

帮助大家认识explain,遇到上述问题的时候可以到此来查阅执行计划中每个字段的意思

能根据慢查询的执行计划快速找到问题所在

提供常见的问题原因以及解决方案

explain能干嘛

在了解explain之前,不妨先看下mysql服务大致的逻辑架构图,以对其有一个整体的认识

128b83b3a9bf15e4112baf35c67ed3dc.png

从图中可以看出,我们的sql在查询的时候主要需要经历以下步骤:

与mysql建立连接

查询缓存是否存在,如果有则直接返回结果

解析器,主要是对sql进行解析

查询优化器,主要对sql进行各种优化,包括重写查询、决定表的读取顺序以及选择合适的索引等等。。并产生执行计划

去存储引擎查询结果

而我们使用explain即是去查询优化器查询执行计划

explain字段解释

看一条简单的执行计划

explain select * from t_user where id = 1;

复制代码

48d5b120ca782159cb88b705f99cb74b.png

我们可以看到,一个执行计划会展示12个相关的字段,下面我们对主要字段以及这些字段常见的值进行解释:

id

含义:是一组数字,表示的是查询中执行select子句或者是操作表的顺序

规则:

id不相同的,id值越大越先执行

id相同的,从上到下顺序执行

select_type

常见的值以及描述如下

描述

SIMPLE

简单的SELECT语句(不包括UNION操作或子查询操作)

PRIMARY

查询中最外层的SELECT(如两表做UNION或者存在子查询的外层的表操作为PRIMARY,内层的操作为UNION)

UNION

UNION操作中,查询中处于内层的SELECT,即被union的SELECT

SUBQUERY

子查询中的SELECT

DERIVED

表示包含在 From 子句中的 Select 查询

UNION RESULT

union的结果,此时id为NULL

table

涉及的表

type(重要)

这列很重要,显示了连接使用哪种类型,有无使用索引,

常见的值从最好到最差如下

system > const > eq_ref > ref > range > index > all

各值的描述如下

描述

system

表只有一行,MyISAM引擎所有

const

常量连接,表最多只有一行匹配,通常用于主键或者唯一索引比较时,如:

select * from t_user where id = 1;

eq_ref

表关联查询时,对于前表的每一行,后表只有一行与之匹配。

(1) join查询

(2) 命中主键或者非空唯一索引

ref

只使用了索引的最左前缀或者使用的索引是非唯一索引、非主键索引

range

between,in,>等都是典型的范围(range)查询

index

需要扫描索引上的全部数据,如:

select count(*) from t_user;

all

全表扫描

possible_keys

表示可能用到的索引

key

表示最终用到的key

ref

显示索引的哪一列被使用了,有时候会是一个常量:表示哪些列或常量被用于查找索引列上的值

rows

估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数, 原则上 rows 越少越好。

filtered

查询结果的行数占上面rows的百分比

Extra(重要)

这一列也很重要,主要展示额外的信息说明,能够给出让我们深入理解执行计划进一步的细节信息

常见的值及描述如下

描述

Using filesort

当order by 无法利用索引完成排序时,优化器不得不选择合适的算法从内存或者磁盘进行排序

Using temporary

使用了临时表

Using index

select后面的查询字段在索引中就可以取到,无需再回表了,即所谓的覆盖索引,这种查询性能很好

Using index condition

mysql5.6之后引入了ICP(索引条件下推)

Using where

Mysql 服务器在存储引擎检索行后再进行过滤

优化原则

通常有以下几种优化原则:

让主要查询语句使用到合适的索引,type出现ALL(全表扫描)需格外注意,同时建立合适的索引以减少possible_keys的数量

type最好能达到ref级别

Extra列出现Using temporary、Using filesort(文件排序)务必去除

优化思路

针对上面提到的几点优化原则,提供如下的优化思路

针对优化原则1,2

上述1,2点其实都可以通过优化索引来达到目的,而要想让我们建的索引达到最优,则需要依据一个原则: 三星索引原则

简单描述就是

☆: where后条件匹配的索引列越多扫描的数据将越少

比如组合索引(a,b,c),最好在where后面能同时用到索引上的a,b,c这三列

☆: 避免再次排序

简单来说,就是排序字段尽量使用索引字段,因为索引默认是排好序的,使用索引字段排序可以避免再次排序

☆: 索引行包含查询语句中所有的列,即覆盖索引

基于这一点,我们应该少用select*来查询,以增加覆盖索引的可能性

如果你的索引能集齐上述三颗星,则说明你的索引是最优的索引!

针对优化原则3

我们创建如下表,并插入一些数据

用户表

CREATE TABLE `t_user` (

`id` bigint(11) NOT NULL AUTO_INCREMENT,

`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,

`age` int(11) DEFAULT NULL,

`group_id` bigint(20) DEFAULT NULL,

PRIMARY KEY (`id`) USING BTREE,

INDEX `idx_name`(`name`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 1240277101395107842 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

复制代码

分组表

CREATE TABLE `t_group` (

`id` bigint(20) NOT NULL,

`group_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,

PRIMARY KEY (`id`) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

复制代码

Using filesort

order by 的字段不在where条件中

下面这条sql会出现Using filesort

select * from t_user where group_id = 2 and age = 32 order by name;

复制代码

4f3a156ca3ae5a47763471df9e717260.png

但是下面这条sql不会

select * from t_user where group_id = 2 and age = 32 order by group_id ;

复制代码

638006f91aae11effc90e1cffb62c4ea.png

组合索引跨列

举例:给t_user表创建索引(name,age,group_id)

下面这条sql排序会出现Using filesort

select * from t_user where name= '李A' order by group_id;

复制代码

c1a0f2605e58b8db1fd070a51fca39f1.png

但是下面这条就不会

select * from t_user where name = '李A' order by age;

复制代码

8c1bbaf40b9ecd210010d18c75594d5e.png

因为第一条查询order by跳过了age,直接使用了group_id;删除索引(name,age,group_id);

由于group by第一步默认进行了排序,所以当group by 的字段满足上述条件是,也会出现Using filesort,可以在group by后面加上order by null取消排序

Using temporary

临时表的出现对性能影响是很大的,主要会出现在以下情况中

分组字段不在where条件后面,并且group by字段不是最终使用到的索引,原因有点类似于上面的Using filesort

下面这条sql会出现Using temporary

select * from t_user where group_id = 2 and name= '李A' group by age;

复制代码

61710e7759584076193293d16d2e25d9.png

但是下面这条sql不会

select * from t_user where name = '李A' and age = 21 group by age;

复制代码

结论: where哪些字段,就group by 哪些字段

表连接中,order by的列不是驱动表中的

如下sql是会创建临时表的

explain select * from t_user t1 left join t_group t2 on t1.group_id = t2.id order by t2.id;

复制代码

931d5e6330c09795cf0e507bf921a574.png

因为t1和t2连接的时候,t1是驱动表,但是排序使用了被驱动表t2中的字段。改为t1的字段排序就不会出现临时表了,这里就不举例了。

结论: 连接查询的时候,排序字段使用驱动表的字段

order by和group by的子句不一样时

explain select * from t_user group by group_id order by `name`;

复制代码

e68023fdb070879da31c60e53049ef1c.png

这种情况只能尽量使用同一个字段来分组和排序了,否则无法避免

distinct查询并且加上order by时

explain select DISTINCT(`name`) from t_user order by age;

复制代码

f9909cdbe741c891ce5dec395a015e30.png

这种情况有时候无法避免,只能尽量将distinct的字段和order by的字段使用相同的索引。还有会出现临时表的情况有: from 中的子查询、union,这里就不一一举例了。

总结

sql优化已经是我们后端开发的内化技能之一了,在学习框架,设计思想的同时,不要忘记打牢基础,希望各位能够有所收获。

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[SQL优化-使用explain分析SQL执行计划]http://www.zyiz.net/tech/detail-125125.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值