设为首页 收藏本站
查看: 806|回复: 0

[经验分享] MySQL查询优化之explain的深入解析

[复制链接]

尚未签到

发表于 2018-10-8 06:00:14 | 显示全部楼层 |阅读模式
  在分析查询性能时,考虑EXPLAIN关键字同样很管用。EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作、以及MySQL成功返回结果集需要执行的行数。explain 可以帮助我们分析 select 语句,让我们知道查询效率低下的原因,从而改进我们查询,让查询优化器能够更好的工作。
  一、MySQL 查询优化器是如何工作的
  MySQL 查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行。最终目标是提交 SELECT 语句查找数据行,而不是排除数据行。优化器试图排除数据行的原因在于它排除数据行的速度越快,那么找到与条件匹配的数据行也就越快。如果能够首先进行最严格的测试,查询就可以执行地更快。
  EXPLAIN 的每个输出行提供一个表的相关信息,并且每个行包括下面的列:
  项
  说明
  id
  MySQL Query  Optimizer 选定的执行计划中查询的序列号。表示查询中执行 select 子句或操作表的顺序,id 值越大优先级越高,越先被执行。id 相同,执行顺序由上至下。
  select_type 查询类型
  说明
  SIMPLE
  简单的 select 查询,不使用 union 及子查询
  PRIMARY
  最外层的 select 查询
  UNION
  UNION 中的第二个或随后的 select 查询,不依赖于外部查询的结果集
  DEPENDENT UNION
  UNION 中的第二个或随后的 select 查询,依赖于外部查询的结果集
  SUBQUERY
  子查询中的第一个 select 查询,不依赖于外部查询的结果集
  DEPENDENT  SUBQUERY
  子查询中的第一个 select 查询,依赖于外部查询的结果集
  DERIVED
  用于 from 子句里有子查询的情况。 MySQL 会递归执行这些子查询, 把结果放在临时表里。
  UNCACHEABLE  SUBQUERY
  结果集不能被缓存的子查询,必须重新为外层查询的每一行进行评估。
  UNCACHEABLE  UNION
  UNION 中的第二个或随后的 select 查询,属于不可缓存的子查询
  项
  说明
  table
  输出行所引用的表
  type 重要的项,显示连接使用的类型,按最优到最差的类型排序
  说明
  system
  表仅有一行(=系统表)。这是 const 连接类型的一个特例。
  const
  const 用于用常数值比较 PRIMARY KEY 时。当查询的表仅有一行时,使用 System。
  eq_ref
  const 用于用常数值比较 PRIMARY KEY 时。当查询的表仅有一行时,使用 System。
  ref
  连接不能基于关键字选择单个行,可能查找到多个符合条件的行。叫做 ref 是因为索引要跟某个参考值相比较。这个参考值或者是一个常数,或者是来自一个表里的多表查询的结果值。
  ref_or_null
  如同 ref, 但是 MySQL 必须在初次查找的结果里找出 null 条目,然后进行二次查找。
  index_merge
  说明索引合并优化被使用了。
  unique_subquery
  在某些 IN 查询中使用此种类型,而不是常规的 ref:value IN (SELECT primary_key FROM single_table  WHERE some_expr)
  index_subquery
  在某些 IN 查询中使用此种类型 , 与 unique_subquery 类似,但是查询的是非唯一性索引: value IN  (SELECT key_column FROM single_table WHERE some_expr)
  range
  只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引。当使用=、 、>、>=、  select_type: SIMPLE
  table: article
  type: ALL
  possible_keys: NULL
  key: NULL
  key_len: NULL
  ref: NULL
  rows: 3
  Extra: Using where; Using filesort
  1 row in set (0.00 sec)
  很显然,type 是 ALL,即最坏的情况。Extra 里还出现了 Using filesort,也是最坏的情况。优化是必须的。
  嗯,那么最简单的解决方案就是加索引了。好,我们来试一试。查询的条件里即 where 之后共使用了category_id,comments,views 三个字段。那么来一个联合索引是最简单的了。
  复制代码代码如下:
  ALTER TABLE `article` ADD INDEX x ( `category_id` , `comments`, `views` );
  结果有了一定好转,但仍然很糟糕:
  复制代码代码如下:
  *************************** 1. row ***************************

  >  select_type: SIMPLE
  table: article
  type: range
  possible_keys: x
  key: x
  key_len: 8
  ref: NULL
  rows: 1
  Extra: Using where; Using filesort
  1 row in set (0.00 sec)
  type 变成了range,这是可以忍受的。但是 extra 里使用 Using filesort 仍是无法接受的。但是我们已经建立了索引,为啥没用呢?这是因为按照 BTree 索引的工作原理,先排序 category_id,如果遇到相同的 category_id 则再排序 comments,如果遇到相同的 comments 则再排序 views。当 comments 字段在联合索引里处于中间位置时,因comments > 1 条件是一个范围值(所谓 range),MySQL 无法利用索引再对后面的 views 部分进行检索,即 range 类型查询字段后面的索引无效。
  那么我们需要抛弃 comments,删除旧索引:
  复制代码代码如下:
  DROP INDEX x ON article;
  然后建立新索引:
  复制代码代码如下:
  ALTER TABLE `article` ADD INDEX y ( `category_id` , `views` ) ;
  接着再运行查询:
  复制代码代码如下:
  *************************** 1. row ***************************

  >  select_type: SIMPLE
  table: article
  type: ref
  possible_keys: y
  key: y
  key_len: 4
  ref: const
  rows: 1
  Extra: Using where
  1 row in set (0.00 sec)
  可以看到,type 变为了 ref,Extra 中的 Using filesort 也消失了,结果非常理想。
  再来看一个多表查询的例子。

  首先定义 3个表>  复制代码代码如下:
  CREATE TABLE IF NOT EXISTS `class` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `card` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
  );
  CREATE TABLE IF NOT EXISTS `book` (
  `bookid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `card` int(10) unsigned NOT NULL,
  PRIMARY KEY (`bookid`)
  );
  CREATE TABLE IF NOT EXISTS `phone` (
  `phoneid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `card` int(10) unsigned NOT NULL,
  PRIMARY KEY (`phoneid`)
  ) engine = innodb;
  然后再分别插入大量数据。插入数据的php脚本:
  复制代码代码如下:
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-615027-1-1.html 上篇帖子: 二进制安装MySQL5.5.57 下篇帖子: 远程连接mysql 授权方法详解
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表