如何使用 EXPLAIN 精准查看执行计划?
在上一篇中 如何使用慢查询快速定位执行慢的 SQL?定位了查询慢的 SQL 之后,我们就可以使用 EXPLAIN 工具做针对性的分析,比如我们想要了解 product_comment 和 user 表进行联查的时候所采用的的执行计划,可以使用下面这条语句:
EXPLAIN SELECT comment_id, product_id, comment_text, product_comment.user_id, user_name FROM product_comment JOIN user on product_comment.user_id = user.user_id
EXPLAIN 可以帮助我们了解数据表的读取顺序、SELECT 子句的类型、数据表的访问类型、可使用的索引、实际使用的索引、使用的索引长度、上一个表的连接匹配条件、被优化器查询的行的数量以及额外的信息(比如是否使用了外部排序,是否使用了临时表等)等。
SQL 执行的顺序是根据 id 从大到小执行的,也就是 id 越大越先执行,当 id 相同时,从上到下执行。
数据表的访问类型所对应的 type 列是我们比较关注的信息。type 可能有以下几种情况:
在这些情况里,all 是最坏的情况,因为采用了全表扫描的方式。index 和 all 差不多,只不过 index 对索引表进行全扫描,这样做的好处是不再需要对数据进行排序,但是开销依然很大。如果我们在 Extral 列中看到 Using index,说明采用了索引覆盖,也就是索引可以覆盖所需的 SELECT 字段,就不需要进行回表,这样就减少了数据查找的开销。
比如我们对 product_comment 数据表进行查询,设计了联合索引composite_index (user_id, comment_text),然后对数据表中的comment_id、comment_text、user_id这三个字段进行查询,最后用 EXPLAIN 看下执行计划:
EXPLAIN SELECT comment_id, comment_text, user_id FROM product_comment
你能看到这里的访问方式采用了 index 的方式,key 列采用了联合索引,进行扫描。Extral 列为 Using index,告诉我们索引可以覆盖 SELECT 中的字段,也就不需要回表查询了。
range 表示采用了索引范围扫描,这里不进行举例,从这一级别开始,索引的作用会越来越明显,因此我们需要尽量让 SQL 查询可以使用到 range 这一级别及以上的 type 访问方式。
index_merge 说明查询同时使用了两个或以上的索引,最后取了交集或者并集。比如想要对comment_id=500000 或者user_id=500000的数据进行查询,数据表中 comment_id 为主键,user_id 是普通索引,我们可以查看下执行计划:
EXPLAIN SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE comment_id = 500000 OR user_id = 500000
你能看到这里同时使用到了两个索引,分别是主键和 user_id,采用的数据表访问类型是 index_merge,通过 union 的方式对两个索引检索的数据进行合并
ref 类型表示采用了非唯一索引,或者是唯一索引的非唯一性前缀。比如我们想要对user_id=500000的评论进行查询,使用 EXPLAIN 查看执行计划:
EXPLAIN SELECT comment_id, comment_text, user_id FROM product_comment WHERE user_id = 500000
这里 user_id 为普通索引(因为 user_id 在商品评论表中可能是重复的),因此采用的访问类型是 ref,同时在 ref 列中显示 const,表示连接匹配条件是常量,用于索引列的查找。
eq_ref 类型是使用主键或唯一索引时产生的访问方式,通常使用在多表联查中。假设我们对product_comment表和 usre 表进行联查,关联条件是两张表的 user_id 相等,使用 EXPLAIN 进行执行计划查看:
EXPLAIN SELECT * FROM product_comment JOIN user WHERE product_comment.user_id = user.user_id
需要说明的是 const 类型和 eq_ref 都使用了主键或唯一索引,不过这两个类型有所区别,const 是与常量进行比较,查询效率会更快,而 eq_ref 通常用于多表联查中。
system 类型一般用于 MyISAM 或 Memory 表,属于 const 类型的特例,当表只有一行时连接类型为 system
EXPLAIN SELECT * FROM test_myisam
你能看到除了 all 类型外,其他类型都可以使用到索引,但是不同的连接方式的效率也会有所不同,效率从低到高依次为 all < index < range < index_merge < ref < eq_ref < const/system。我们在查看执行计划的时候,通常希望执行计划至少可以使用到 range 级别以上的连接方式,如果只使用到了 all 或者 index 连接方式,我们可以从 SQL 语句和索引设计的角度上进行改进。
- 《干货系列》SQL语句-知无不言言无不尽
- OutOfMemoryError异常系列之方法区溢出和运行时常量溢出池溢出
- 代码转换工具 Code Converter 2013
- OutOfMemoryError异常系列之Java堆溢出
- android ndk之hello world
- ScheduledExecutorService和timer的异同
- 【精心解读】关于Jupyter Notebook的28个技巧
- Web项目接口自动化测试框架搭建
- 一文读懂Hadoop、HBase、Hive、Spark分布式系统架构
- 《Spring敲门砖之基础教程第一季》 第二章(1) Spring框架之IOC首例-HelloWorld
- Java9中的GC调优基础
- javascript深入理解js闭包
- https连接的前几毫秒发生了什么
- android自定义view实现progressbar的效果
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 3分钟短文:Laravel应用跟用户打交道,就从拿到他们的数据开始!
- leetcode之字符串压缩
- Android如何获取屏幕、状态栏及标题栏的高度详解
- Android中FloatingActionButton的显示与隐藏示例
- Android 中RecyclerView顶部刷新实现详解
- Android开发实现图片平移、缩放、倒影及旋转功能的方法
- Grafana + InfluxDB 实现 Jmeter 压测的图形化监控
- Android 浮动编辑框的具体实现代码
- Android实现Path平滑的涂鸦效果实例
- Android CameraManager类详解
- Android开发实现自定义水平滚动的容器示例
- Android Studio开发之 JNI 篇的简单示例
- Android自定义View播放Gif动画的示例
- Android下拉框PopupWindow使用详解
- Android实现自动文本框提示功能