性能分析与 EXPLAIN 详解

2021-02-10  本文已影响0人  L_又不是不能用

一、sql查询慢原因及优化

1、导致慢 SQL 的原因

在遇到慢 SQL 情况时,不能简单的把原因归结为 SQL 编写问题(虽然这是最常见的因素),实际上导致慢 SQL 有很多因素,甚至包括硬件和 mysql 本身的 bug。根据出现的概率从大到小,罗列如下:
1、 SQL编写问题
2、锁
3、业务实例相互干绕对 IO/CPU 资源争用
4、服务器硬件
5、MYSQL BUG

2、由 SQL 编写导致的慢 SQL 优化

针对SQL编写导致的慢 SQL,优化起来还是相对比较方便的。正如上一节提到的正确的使用索引能加快查询速度,那么我们在编写 SQL 时就需要注意与索引相关的规则:

除了上述索引使用规则外,SQL 编写时还需要特别注意一下几点:

二、性能分析与 EXPLAIN 详解

性能优化概述

MySQL Query Optimizer 的作用

1、MySQL 中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(MySQL认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)
2、当客户端向MySQL 请求一条Query,命令解析器模块完成请求分类,区别出是SELECT并转发给MySQL Query Optimizer时,MySQL Query Optimizer 首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对Query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析 Query中的Hint信息(如果有),看显示Hint信息是否可以完全确定该Query的执行计划。如果没有Hint 或Hint 信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。

MySQL 常见瓶颈

1、CPU 瓶颈:CPU在饱和的时候一般发生在数据装入在内存或从磁盘上读取数据时候
2、IO 瓶颈:磁盘I/O瓶颈发生在装入数据远大于内存容量时
3、服务器硬件的性能瓶颈:top、free、iostat和vmstat来查看系统的性能状态

三、Explain

是什么?Explain 是查看执行计划

1、使用EXPLAIN关键字可以模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈
2、官网地址:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

能干嘛?

1、表的读取顺序(id 字段)
2、数据读取操作的操作类型(select_type 字段)
3、哪些索引可以使用(possible_keys 字段)
4、哪些索引被实际使用(keys 字段)
5、表之间的引用(ref 字段)
6、每张表有多少行被优化器查询(rows 字段)

怎么玩?

Explain + SQL语句

mysql> explain select * from tbl_emp;
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | tbl_emp | ALL  | NULL          | NULL | NULL    | NULL |    8 | NULL  |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

Explain 详解

id:select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
id 取值的三种情况:
1、id相同,执行顺序由上至下

id相同的情况
2、id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
id不同的情况
3、id有相同有不同,同时存在:id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行;衍生=DERIVED
id有相同有不同的情况
select_type:查询的类型,主要用于区别普通查询、联合查询、子查询等复杂查询

UNION 和 UNION RESULT举例

explain
    -> select * from tbl_emp e left join tbl_dept d on e.deptId = d.id
    -> union
    -> select * from tbl_emp e right join tbl_dept d on e.deptId = d.id;
+----+--------------+------------+------+---------------+------------+---------+-----------+------+----------------------------------------------------+
| id | select_type  | table      | type | possible_keys | key        | key_len | ref       | rows | Extra                                              |
+----+--------------+------------+------+---------------+------------+---------+-----------+------+----------------------------------------------------+
|  1 | PRIMARY      | e          | ALL  | NULL          | NULL       | NULL    | NULL      |    8 | NULL                                               |
|  1 | PRIMARY      | d          | ALL  | PRIMARY       | NULL       | NULL    | NULL      |    5 | Using where; Using join buffer (Block Nested Loop) |
|  2 | UNION        | d          | ALL  | NULL          | NULL       | NULL    | NULL      |    5 | NULL                                               |
|  2 | UNION        | e          | ref  | fk_dept_Id    | fk_dept_Id | 5       | db01.d.id |    1 | NULL                                               |
| NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL       | NULL    | NULL      | NULL | Using temporary                                    |
+----+--------------+------------+------+---------------+------------+---------+-----------+------+----------------------------------------------------+
5 rows in set (0.00 sec)
table:显示这一行的数据是关于哪张表的
type:访问类型排列,显示查询使用了何种类型

1、type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是:system>const>eq_ref>ref>fultext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
2、挑重要的来说:system>const>eq_ref>ref>range>index>ALL,一般来说,得保证查询至少达到range级别,最好能达到ref。


从最好到最差依次是:system>const>eq_ref>ref>range>index>ALL
1、system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计
2、const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,MySQL就能将该查询转换为一个常量


3、eq_ref:唯一性索引,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描

4、ref:非唯一索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体

5、range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引一般就是在你的where语句中出现了between、<、>、in等的查询这种范围扫描索引扫描比全表扫描要好,因为他只需要开始索引的某一点,而结束于另一点,不用扫描全部索引

6、index:Full Index Scan,使用了覆盖索引,index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘数据库文件中读的)

7、ALL:FullTable Scan,将遍历全表以找到匹配的行(全表扫描)

备注:一般来说,得保证查询只是达到range级别,最好达到ref
possible_keys

1、显示可能应用在这张表中的索引,一个或多个
2、若查询涉及的字段上存在索引,则该索引将被列出,但不一定被查询实际使用

key

1、实际使用的索引,如果为null,则没有使用索引
2、若查询中使用了覆盖索引,则该索引仅出现在key列表中


key_len

1、表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好
2、key_len显示的值为索引最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的,在组合索引中可以通过key_len来判断用到的索引个数


ref

1、显示索引哪一列被使用了,如果可能的话,最好是一个常数。哪些列或常量被用于查找索引列上的值
2、由key_len可知t1表的索引idx_col1_col2被充分使用,t1表的col1匹配t2表的col1,t1表的col2匹配了一个常量,即’ac’


rows

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


Extra:包含不适合在其他列中显示但十分重要的额外信息

1、Using filesort(文件排序)

4、Using where:where子句中除索引字段 还包含索引之外的字段

5、Using index condition

6、Using join buffer:表明使用了连接缓存
7、impossible where:where子句的值总是false,不能用来获取任何元组


8、select tables optimized away:在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
9、distinct:优化distinct,在找到第一匹配的元组后即停止找同样值的工作

Explain 热身 Case

1、第一行(执行顺序4):id列为1,表示是union里的第一个select,select_type列的primary表示该查询为外层查询,table列被标记为<derived3>,表示查询结果来自一个衍生表,其中derived3中3代表该查询衍生自第三个select查询,即id为3的select。【select d1.name ...】
2、第二行(执行顺序2):id为3,是整个查询中第三个select的一部分。因查询包含在from中,所以为derived。【select id, name from t1 where other_column= ' '】
3、第三行(执行顺序3):select列表中的子查询select_type为subquery,为整个查询中的第二个select。【select id from t3】
4、第四行(执行顺序1):select_type为union,说明第四个select是union里的第二个select,最先执行【select name, id from t2】
5、第五行(执行顺序5):代表从union的临时表中读取行的阶段,table列的<union1, 4>表示用第一个和第四个select的结果进行union操作。【两个结果进行uinion操作】


上一篇下一篇

猜你喜欢

热点阅读