mysql执行计划 优化_MySQL优化-explain执行计划详解

文章目录MySQL Query Optimizer简介MySQL常见瓶颈覆盖索引(Covering Index), 又称为索引覆盖执行计划(Explain)详解简介Explain能得到哪些信息使用方法执行计划信息详解idselect_typetabletypepossible_keys, keykey_lenrefrowsExtra

MySQL Query Optimizer简介

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

当客户端向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等命令来查看系统性能状态

程序中SQL语句问题, Explain查看执行计划

上面的三个问题一般会有对应的运维人员去处理, 作为开发人员最需要关注的是SQL问题

覆盖索引(Covering Index), 又称为索引覆盖

这个概念下面需要用到,先放在这里

理解方式一 : 就是SELECT的数据列只用从索引中就能够取到, 不必读取数据行, MySQL可以利用索引返回SELECT列表中的字段, 而不必根据索引再次读取数据文件, 换句话说, 查询列要被所建的索引覆盖。

理解方式二 : 索引是高效找到行的一个方法, 但是一般数据库也能使用索引找到一个列的数据, 因此它不必读取整个行。毕竟索引的叶子节点存储了它们索引的数据; 当能通过读取索引就可以得到想要的数据, 那就不需要读取行了。一个索引包含了(或覆盖了)满足查询结果的数据就叫做覆盖索引

注意 :

如果要使用覆盖索引, 一定要注意SELECT列表中只取出需要的列, 不能SELECT *, 因为如果将所有字段一起做索引会导致索引文件过大, 查询性能下降。

执行计划(Explain)详解

简介

使用EXPLAIN关键字可以模拟优化器执行SQL的查询语句, 从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈

Explain能得到哪些信息

表的读取顺序

数据读取操作的操作类型

哪些索引可以使用

哪些索引被实际使用

表之间的引用

每张表有多少行被优化器查询

使用方法

explain + SQL语句

执行计划包含的信息:

579a1465f6f698ebe16b4c4c7e4ac1cd.png

执行计划信息详解

id

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

id相同 : 执行顺序由上向下

ca429e21e846665e9e4a1373f0d0a0b8.png

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

19052c2b91e9c64fde250a79df09554b.png

ID相同不同, 同时存在 : id如果相同.可以认为是一组, 从上往下顺序执行; 在所有组中, id值越大, 优先级越高, 越先执行

42eef93faf57b4ea7175c9f03e207fc6.png

derived表示衍生, 第一行中的derived2表示, 这个虚表是由id为2的语句所衍生的

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

table

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

type

访问类型, 显示查询使用了何种类型, 从最好到最差依次是 :

system>const>eq_ref>ref>range>index>ALL

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

system : 表只有一行记录(等于系统表), 这是const类型的特例, 平时不会出现

const : 表示通过索引依次就找到了, const用于比较primary key或者unique索引。因为只匹配一行数据, 索引很快, 如将主键置于where列表中, MySQL就能将该查询转换为一个常量

57b9cdfff0360108c2fdcaef1a4bb87c.png

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

aa524bde0e9f07f5d189ec236431e3be.png

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

d3e2851c31489d13dfd0f2ecd2d0b325.png

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

3fce35cab1531428adb1939744fa4593.png

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

4bc96d611c090d1c951f89304a412b58.png

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

17889c41f1456a731456f316e31c742f.png

possible_keys, key

possible_keys :

显示可能应用在这张表中的索引, 一个或多个。

查询涉及到的字段是若存在索引, 则该索引将被列出, 但不一定被查询实际使用

key :

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

查询中若使用了覆盖索引, 则该索引仅出现在key列表中

覆盖索引演示 :

6ad7c62c402873afba128a3f6276b40c.png

possible_keys,key演示 :

4f8c49ecb5f4504b7bceffdfe2d1f57b.png

key_len

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

key_len显示的值为索引字段的最大可能长度, 并非实际使用长度, 即key_len是根据表定义计算而得, 不是通过表内检索获得的

ref

显示索引的哪一列被使用了, 如果可能的话, 最好是一个常数。哪些列或常量被用于查找索引列上的值

4a6a40f55350935a63f5c2e462b9061d.png

rows

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

Extra

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

Using filesort : 说明MySQL会对数据使用一个外部的索引排序, 而不是按照表内索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为"文件排序"。

2a99bb8b08ce7a2c4cc82f8672121a49.png

Using temporary : 使用了临时表保存中间结果, MySQL在对查询结果排序时使用了临时表。常见于排序order by和分组查询group by。

bd136a919b0e69b59ba827c7dc2f9582.png

Using index : 表示相应的SELECT操作中使用了覆盖索引(Covering Index), 避免了访问表的数据行, 效率还可以

如果同时出现Using where, 表明索引被用来执行索引键值的查找;

如果没有出现同时出现Using where, 表明索引用来读取数据而非执行查找动作

244444509818e903f4ec31955942eeb5.png

Using where : 使用了where过滤

Using join buffer : 使用了连接缓存

Impossible WHERE : where子句值总是false, 不能用来获取任何数据, 如name=‘张三’ and name=‘李四’

SELECT tables optimized away : 在没有group by子句的情况下, 基于索引优化MIN/MAx操作或者对于MyIsam存储引擎优化COUNT(*)操作, 不必等到执行阶段再进行计算, 查询执行计划生成阶段即完成优化。

distinct : 优化distinct操作, 在找到第一匹配的元组后即停止找同样值的动作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值