性能分析
要说sql有问题,需要拿出证据,因此需要性能分析
Mysql查询优化器(Mysql Query Optimizer)
- Mysql中有专门负责优化SELECT语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(它认为最优的数据检索方式,不见得是DBA认为是最优的,这部分最耗费时间,如果知道mysql底层是如何执行一条sql,可以帮助我们更好地优化sql)
- 当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出是 SELECT 转发给MysQL Query 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是什么?
EXPLAIN:SQL的执行计划,使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理SQL语句的,进而分析查询语句或是表结构的性能瓶颈。
EXPLAIN怎么使用?
语法:explain关键字 + 所写的SQL。
【表格形式查看】
explain select * from tbl_emp;
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhQm9gzw-1687613436534)(assets/1687613388315-15.png)]](https://img-blog.csdnimg.cn/980237b5bb4842df96d5ce10aed381e2.png)
【列形式查看】
mysql> explain select * from pms_category \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pms_category
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1425
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)
EXPLAIN能干嘛?
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F2t4Yivo-1687613436534)(assets/1687613388316-16.png)]](https://img-blog.csdnimg.cn/8907e10276bf41d28f6b9860292f4d77.png)
通过上面的表格可以查看以下信息:
id列 了解表的读取顺序
值有以下三种情况:
- id相同,执行顺序由上至下。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sOkucRTf-1687613436535)(assets/1687613388316-17.png)]](https://img-blog.csdnimg.cn/1269ab47bdd44511877ea944861934dd.png)
- id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-87bemwc1-1687613436535)(assets/1687613388316-18.png)]](https://img-blog.csdnimg.cn/f20c68fb817749a396f35ef9b67fc1ca.png)
- id相同和不同 同时存在。永远是id大的优先级最高,id相等的时候从上到下顺序执行。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bwb5mibD-1687613436535)(assets/1687613388316-19.png)]](https://img-blog.csdnimg.cn/d42090eada1c46d89525afed64e5801e.png)
总结:id相同上下顺序走,不同id大的先走
select_type列 数据读取操作的操作类型。
select_type:数据查询的类型,主要是用于区别,普通查询、联合查询、子查询等复杂查询。
【常见值】
- SIMPLE:简单的- SELECT查询,查询中不包含子查询或者- UNION。
- PRIMARY:查询中如果包含任何复杂的子部分,最外层查询则被标记为- PRIMARY。
- SUBQUERY:在- SELECT或者- WHERE子句中包含了子查询。
- DERIVED:在- FROM子句中包含的子查询被标记为- DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中。
- UNION:如果第二个- SELECT出现在- UNION之后,则被标记为- UNION;若- UNION包含在- FROM子句的子查询中,外层- SELECT将被标记为- DERIVED。
- UNION RESULT:从- UNION表获取结果的- SELECT。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C2S9AWRV-1687613436536)(assets/1687613388316-20.png)]](https://img-blog.csdnimg.cn/02ff1a619af041d68de3f483792abcb8.png)
table列 表的名字
标题已经通俗易懂了,哈哈
type列 访问类型详解及排列
【type列常见值】
- system:一张表只有一行记录(如系统参数表,每个参数字段只存储一个值),这是- const类型的特例(平时不会出现,这个也可以忽略不计)
- const:表示通过索引一次就找到了,- const用于比较- primary key或者- unique索引。因为只匹配一行数据,所以很快。如将主键置于- where列表中,MySQL就能将该查询转化为一个常量。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MQ9eNkRR-1687613436536)(assets/1687613388316-21.png)]](https://img-blog.csdnimg.cn/c8e3f70dedbb40e6a4c1c37d718c6145.png)
- eq_ref:唯一性索引扫描,读取本表中和关联表表中的每行组合成的一行,查出来只有一条记录。除了- system和- const类型之外, 这是最好的连接类型。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xqx8CeCU-1687613436536)(assets/1687613388317-22.png)]](https://img-blog.csdnimg.cn/5a2d7d2184384e278e97999a0e70bb7a.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Exwr438-1687613436536)(assets/1687613388317-23.png)]](https://img-blog.csdnimg.cn/2a78f5bd8da249aaa4ba3ff015d6f3ab.png)
- ref:非唯一性索引扫描,返回本表和关联表某个值匹配的所有行,查出来有多条记录。
【例子1】
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Julc3UOq-1687613436537)(assets/1687613388317-24.png)]](https://img-blog.csdnimg.cn/d9015ee712154d4cbf458a5e36f7d796.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y9binrsO-1687613436537)(assets/1687613388317-25.png)]](https://img-blog.csdnimg.cn/0765bdca1dc2419abe7b6de988af7d86.png)
【例子2】
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2NbJVrIg-1687613436537)(assets/1687613388317-26.png)]](https://img-blog.csdnimg.cn/8d21e67883334736a230801bba94ce15.png)
- range:只检索给定范围的行,一般就是在- WHERE语句中出现了- BETWEEN、- < >、- in等的查询。这种范围扫描索引比全表扫描要好,因为它只需要开始于索引树的某一点,而结束于另一点,不用扫描全部索引。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HCwOufiN-1687613436538)(assets/1687613388317-27.png)]](https://img-blog.csdnimg.cn/285eba62f0be47459d43371f39ea04d4.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0SWW6bk3-1687613436538)(assets/1687613388317-28.png)]](https://img-blog.csdnimg.cn/405caae0afef42fab544f4ffb21c4514.png)
- index:- Full Index Scan,全索引扫描,- index和- ALL的区别为- index类型只遍历索引树,不用全表扫描。也就是说虽然- ALL和- index都是读全表,但是- index是从索引中读的,- ALL是从磁盘中读取的。**因为索引文件通常比数据文件小,所以Index往往比ALL快。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sdDYMVXw-1687613436538)(assets/1687613388317-29.png)]](https://img-blog.csdnimg.cn/18876d6672394875a97b9ef0637951a8.png)
- ALL:- Full Table Scan,没有用到索引,全表扫描。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uvSsDYlB-1687613436538)(assets/1687613388317-30.png)]](https://img-blog.csdnimg.cn/8fc68dfbda1147b3a9d700cc2544f4dd.png)
从最好到最差依次是:
system>const>eq_ref>ref>range>index>ALL。除了ALL没有用到索引,其他级别都用到索引了,表示全表扫描。
**总结:**多看sql的type,如果是All,争取优化成其他的,一般来说,得保证查询至少达到
range级别,最好达到ref。
possible_keys列 哪些索引可能被使用
possible_keys:显示可能应用在这张表中的索引,一个或者多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。
key列 哪些索引被实际使用(判断索引是否失效)
key:实际使用的索引。如果为NULL,则没有使用索引。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fsht2uWC-1687613436539)(assets/1687613388318-31.png)]](https://img-blog.csdnimg.cn/e232bbf3e6d4485f8c8ea8c1b86959d2.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gaUiBGzK-1687613436539)(assets/1687613388318-32.png)]](https://img-blog.csdnimg.cn/c95aebd25aa64e00bd90571cab819cb2.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rqS2jI2D-1687613436539)(assets/1687613388318-33.png)]](https://img-blog.csdnimg.cn/5c226842329e402ab32e5d00bc7ea9d7.png)
查询中如果使用了覆盖索引,则该索引仅仅出现在key列表中,不出现在possible_keys中。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChMVE3us-1687613436539)(assets/1687613388318-34.png)]](https://img-blog.csdnimg.cn/f63dd0b0be654083af81f4e75a2c320e.png)
key_len列 索引中使用的字节数
key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
在不损失精度的情况下,长度越短越好。一般是精度要求更高(根据姓名和城市查询一个人比只根据姓名查询一个人精度更高),key_len越长。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CS4ROh7C-1687613436540)(assets/1687613388318-35.png)]](https://img-blog.csdnimg.cn/046db8f732cd411e9069845c55dc6632.png)
key_len计算规则:https://blog.csdn.net/qq_34930488/article/details/102931490
ref列 表之间的引用
ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SGf05tzJ-1687613436540)(assets/1687613388318-36.png)]](https://img-blog.csdnimg.cn/4278bb0e2e224f2eb0d02785dfd5cb91.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4j1S7EUA-1687613436540)(assets/1687613388318-37.png)]](https://img-blog.csdnimg.cn/0197333e564f40558fdd5df3bd900688.png)
由key_len可知t1表的idx col1 col2被充分使用,cl1匹配t2表的col1,co2匹配了一个常量,即’ac’
rows列 每张表有多少行被优化器查询
rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录需要读取的行数。
【没建索引之前】
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l56D4a9I-1687613436540)(assets/1687613388318-38.png)]](https://img-blog.csdnimg.cn/395a32a819ca420384102d9aec438b24.png)
【建索引之后】
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZmRhxs2b-1687613436540)(assets/1687613388318-39.png)]](https://img-blog.csdnimg.cn/a5e5ecde06f44547a964efcd9d6adcb7.png)
Extra列 包含不适合在其他列中显示但十分重要的额外信息
Extra列也会有一系列的值,下面是这些值的解释:
- Using filesort:说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作成为"文件内排序"。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwFIO1Ev-1687613436541)(assets/1687613388318-40.png)]](https://img-blog.csdnimg.cn/34eae464866a4354bd708889ddc48f4f.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RdZ59M0c-1687613436541)(assets/1687613388318-41.png)]](https://img-blog.csdnimg.cn/99e4d3a9803546c2bbc131e0cbb8e07e.png)
总结:出现
Using filesort尽快优化
- Using temporary:使用了临时表(查询结束之后还要删除)保存中间结果,MySQL在対查询结果排序时使用了临时表。常见于排序- order by和分组查询- group by。临时表対系统性能损耗很大。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yvn7VVQm-1687613436541)(assets/1687613388318-42.png)]](https://img-blog.csdnimg.cn/3821be0b394449e39499f4094c627333.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u14pwoiT-1687613436542)(assets/1687613388319-43.png)]](https://img-blog.csdnimg.cn/5885c6697ab743ca8350117f072a41e7.png)
总结:出现
Using temporary尽快优化
- Using index:表示相应的- SELECT操作中使用了覆盖索引,避免访问了表的数据行,- 效率不错!
- 如果同时出现Using where,表示索引被用来执行索引键值的查找;
- 如果没有同时出现Using where,表明索引用来读取数据而非执行查找动作。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9F0VgYqd-1687613436542)(assets/1687613388319-44.png)]](https://img-blog.csdnimg.cn/0bcee0b3b3d547fca8f5e8fd2c199749.png)
覆盖索引:就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说
查询列要被所使用的索引覆盖。 注意:如果要使用覆盖索引,不要写SELECT *,要写出具体的字段。
- Using where:表明使用了- WHERE过滤。
- Using join buffer:使用了连接缓存。如果join特别多,可以调大配置文件的buffer。
- impossible where:- WHERE子句的值总是false,不能用来获取任何元组。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P27F933R-1687613436542)(assets/1687613388319-45.png)]](https://img-blog.csdnimg.cn/0fb94cb2a77b4bb29a26479e8e99da1d.png)
- select tables optimized away:在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算查询执行计划生成的阶段即完成优化。
- distinct:找到第一个匹配的元组后停止同样值的动作
EXPLAIN案例
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oicf24uw-1687613436543)(assets/1687613388319-46.png)]](https://img-blog.csdnimg.cn/9ed639f93c46472487c0c004ddab814e.png)
ets/1687613388319-47.png)]](https://img-blog.csdnimg.cn/f8cd50027a0a45968b6736ee7c3a7abb.png)



















