MySQL 性能分析与执行计划

性能分析

MySQL 查询优化器

MySQL中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中搜集到的统计信息,为客户端请求的Query提供它认为最优的执行计划。

当客户端向MySQL请求一条Query,命令解释器模块完成请求分类,区分出是SELECT并转发给MySQL 查询优化器时,MySQL查询优化器首先会对整条查询进行优化,处理掉一些常量表达式的预算直接换算成常量值。并对Query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析Query中的Hint信息(如果有),看显示Hint信息是否可以完全确定该Query的执行计划。如果没有Hint或Hint信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划。

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

EXPLAIN执行计划

使用explain关键字可以模拟优化器执行sql语句,从而知道MySQL是如何处理你的SQL语句的。

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

执行计划包含以下信息:

  • id
  • select_type
  • table
  • partitions
  • type
  • possible_keys
  • key
  • key_len
  • ref
  • rows
  • filtered
  • Extra
名词解释

id

Select执行的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序

1、id相同,执行顺序由上至下

2、id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

3、id相同又不同即两种情况同时存在,id如果相同,可以认为是一组,从上往下顺序 执行;在所有组中,id值越大,优先级越高,越先执行

示例

在这里插入图片描述

图中构造了一个查询语句(本身没什么意义)为了演示id。

根据规则 id=2的语句 select 1 from user b where b.name is null and a.id=b.id先执行,然后id=1的语句后执行select a.name,a.id from user a where exists (xx)

select_type

查询类型,主要是用于区分普通查询、联合查询、子查询等

PRIMARY:查询中包含子部分,最外层查询则被标记为primary

SUBQUERY/MATERIALIZED:SUBQUERY表示在select 或 where列表中包含了子查询;MATERIALIZED表示where 后面in条件的子查询

UNION:若第二个select出现在union之后,则被标记为union;

UNION RESULT:从union表获取结果的select

以users和user_address表为例 说明执行计划类型

CREATE TABLE `user_address` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userID` int(11) DEFAULT NULL,
  `addr` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uname` varchar(32) NOT NULL,
  `userLevel` int(11) NOT NULL,
  `age` int(11) NOT NULL,
  `phoneNum` char(11) NOT NULL,
  `createTime` datetime NOT NULL,
  `lastUpdate` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`uname`) USING BTREE,
  KEY `idx_union_uname&userLevel&age` (`uname`,`userLevel`,`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

-- 两张表通过userID和id关联

SIMPLE:简单的select查询,查询中不包含子查询或者union

在这里插入图片描述

PRIMARY:查询中包含子查询,最外层的查询被表级为primary

SUBQUERY:表示在select或where列表中包含了子查询

在这里插入图片描述

UNION:若第二个select出现在union,则被标记为union

UNION RESULT:从union表中获取结果的select

在这里插入图片描述

先执行id=2的查询,它的select_type=union;在执行id=1的查询,最后执行id:null的查询。表示由id=1和id=2 union得到的结果

DERIVED(衍生) 是个虚拟表

在这里插入图片描述

table=derived2,表示这张表示从id=2的执行结果衍生出来的。

table

显示这一行的数据是关于哪张表的。

type

访问类型,sql查询优化中一个很重要的指标。

结果值从好到坏依次是: system > const > eq_ref > ref > range > index > ALL

system:表中只有一行记录,这是const类型的特例,平时不会出现,可以忽略不计

const:表示通过索引一次就找到了,const用于比较primary key 或者 unique索引。可类比为使用主键或唯一所引查询。

在这里插入图片描述

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

ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质是也是一种索引访问

在这里插入图片描述

range:只检索给定范围的行,使用一个索引来选择行。Key列显示了使用哪个索引,一般就是在你的where语句中出现了between、<>、in等查询。这种 范围扫描索引比全表扫描好
在这里插入图片描述

index:扫描索引

在这里插入图片描述

ALL:全表扫描

在这里插入图片描述

一般来说,得保证查询至少达到range级别,最好达到ref级别

possible_keys、key

possible_keys 查询过程中有可能用到的索引

key 实际使用的索引,如果为NULL,则没有使用索引

key_len

表示索引中使用的字节数,可以通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好。

key_len显示的值是索引最大可能长度,并非实际使用长度

ref

查询中与其他表关联的字段

在这里插入图片描述

rows

大致估算出找到所需的记录需要读取的行数(越少越好)

filtered

它指返回结果的行占需要读到的行(rows列的值)的百分比 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好

Extra

Using filesort : mysql对数据使用一个外部的文件内容进行了排序,而不是按照表内的索引进行排序读取

在这里插入图片描述

Using temporary: 使用临时表保存中间结果,也就是说mysql在对查询结果排序时使用了临时表,常见于order by 或 group by

在这里插入图片描述

备注:图中语句中userID不是索引,只是普通列

Using index:表示相应的select操作使用了覆盖索引,避免访问了表的数据行,效率不错。如果同时出现using where,表明索引被用来执行索引键值的查找,如果没有同时出现Using where,表明索引用来读取数据而非执行查找操作

在这里插入图片描述

using join buffer:使用了连接缓存,各种join关联

select tables optimized away: 基于索引优化MIN/MAX操作或者MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段在进行计算,查询执行计划生成的阶段即可完成优化

distinct:优化distinct,在找到第一个匹配的元祖后即停止找同样值的工作

发布了116 篇原创文章 · 获赞 23 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zyxwvuuvwxyz/article/details/104595802