本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
性能分析
MySQL Query Optimizer
- Mysql中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)
- 当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出是SELECT并转发给MySQLQuery Optimizer时,MySQL Query Optimizer首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对Query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析Query 中的Hint信息(如果有),看显示Hint信息是否可以完全确定该Query 的执行计划。如果没有Hint 或Hint 信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。
MYSQL 常见瓶颈
- CPU:CPU饱和,一般发生在数据装入内存 / 从磁盘读取数据的时候
- IO:磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
- 服务器硬件:top,free,iostat和vmstat来查看系统性能状态
Explain
-
是什么?
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈
-
干什么?
- 表的读取顺序
- 数据读取操作的操作类型
- 哪写索引可以使用
- 哪写索引实际被使用
- 表之间的引用
- 每张表有多少行被优化器查询
-
怎么用?
-
EXPLAIN + SQL语句
-
执行计划包含的信息
-
-
各字段解释
-
id
SELECT查询的序列号,包含一串数字,表示查询中执行SEKECT子句 / 操作表的顺序
- id相同:执行顺序由上至下
- id不同:如果是子查询,id序号会递增,id值越大优先级越高,越先被执行。
- id相同不同同时存在:id如果相同认为是同一组,顺序执行。所有组中id越大优先级越高。
-
select_type
-
有哪些?
ID SELECT_TYPE 1 SIMPLE 2 PRIMARY 3 SUBQUERY 4 DERIVED 5 UNION 6 UNION RESULT -
查询的类型
主要用于区别普通查询、联合查询、子查询等复杂查询
-
SIMPLE
简单的SELECT查询,查询中不包含子查询和联合查询。
-
PRIMARY
查询中若包含任何复杂的字部份,最外层查询则被标记为PRIMARY
-
SUBQUERY
在SELECT / WHERE列表中包含了子查询
-
DERIVED
derived+序号 表示第 i 个id被加载的衍生i号表
在FROM列表中包含的子查询被标记为衍生,MySQL会递归执行这些子查询,把结果放在临时表里。
-
UNION
若第二个SELECT出现在UNION之后,则被标记为UNION。若UNION包含在FROM子句的子查询中,外层SELECT将被标记为DERIVED
-
UNION RESULT
从UNION表获取结果的SELECT
-
-
-
table
显示该行数据是关于哪张表的 (操作的表对象)
-
type
访问类型排列,从最好到最差依次是:
system > const > eq_ref > ref > range > index > ALL
-
system
表只有一行记录 (等于系统表),这是const类型的特例。
-
const
表示通过一次索引就找到了,const用于比较primary key / unique索引,因为只匹配一行数据所以很快。如果将主键置于where列表中,MySQL就能将该查询转换为一个常量。
-
eq_ref
唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键 / 唯一索引扫描
-
ref (建议)
非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。
-
range (底线)
只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是在你的where语句中出现了between、<、>、in等的查询。这种范围扫描索引比全表扫描要好。
-
index
Full Index Scan,index与ALL的区别为index只遍历索引树,这通常比ALL快。虽然ALL和index都是读全表,但index从索引(内存)中读,ALL是从硬盘中读取的。
-
ALL
Full Table Scan,遍历全表。
-
-
possible_keys
显示可能应用在这张表上的索引,一个或多个。查询涉及到的字段上如果存在索引则将被列出,但不一定被查询实际使用。
-
key
实际使用的索引,如果为NULL则没有使用索引,查询中若使用了覆盖索引[^1],则该索引仅出现在key索引中。
-
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度 (自然是越小越好)。
注:此长度为索引字段最大可能的长度,并非实际使用长度。即key_len是根据表定义计算而得,不是通过表内检索得出。
-
ref
显示哪个索引被使用,哪些列(库.表.列) / 常量(const)被用于查找索引列上的值。
-
rows
根据表统计信息及索引选用情况,大致估算出找到所需记录所需要读取的行数。
-
Extra
包含不适合在其他列中显示但十分重要的信息。
-
Using filesort (危)
说明mysql会对数据使用一个内部的**(执行时新建的)**索引排序,而不是按照表内的索引顺序进行排序、MySQL中无法利用索引完成的排序操作称为“文件排序”。
诱因可能为 未按多重索引顺序 order by,如idx_col1_col2,但group by col2
-
Using temporary (危)
使用了临时表保存中间结果,MySQL在对查询结构排序时使用了临时表。常见于排序order by 和分组查询group by。
-
Using index
注意:如果要使用覆盖索引,一定不能使用select *。因为如果将所有字段一起索引会导致索引文件过大查询性能下降。
表示相应 SELECT 操作使用了覆盖索引[^1],避免了访问表的数据行,效率不错!如果同时出现Using where,表明索引被用来执行索引键值的查找;如果没有同时出现则表明索引用来读取数据而非执行查找动作。
-
Using where
表明使用了where过滤。
-
Using join buffer
表示使用了链接缓存。
-
Impossible where
where子句的值总是false,不能用来获取任何元素。(如 where sex='男' and sex='女')
-
Select tables optimized away
在没有group by子句的情况下,基于索引优化MIN / MAX操作或者对MyISAM储存引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。
-
Distinct
优化distinct操作,再找到第一个匹配的元素后即停止查找直接收工。
-
-