【mysql】mysql 调优之 ——执行计划 explain
1.what is explain(explain 是个什么东东)
explain(解释),在 Mysql 中 作为一个关键词,用来解释 Mysql 是如何执行语句,可以连接 select 、delete、insert、update 语句。
通常我们使用 explain 连接 一条 select 语句,查看运行状态,判断是否需要优化。
2.how to use explain(如何使用呢)
栗子:
explain select s.name,s.id,s.age,s.create_time from student s;
输出:
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | s | NULL | ALL | NULL | NULL | NULL | NULL | 7 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
官方:
EXPLAIN [explain_type] explainable_stmt
explain_type: {
EXTENDED
| PARTITIONS
| FORMAT = format_name
}
explainable_stmt: {
SELECT statement
| DELETE statement
| INSERT statement
| REPLACE statement
| UPDATE statement
}
输出的列名:
- id : select 标识符
- select_type:select 类型
select_type 可选值 |
含义 |
|---|---|
SIMPLE |
简单的 select,没有使用 UNION 或者 子查询 |
PRIMARY |
最外一层的 select |
UNION |
UNION 中第二个或者后面的 select 语句 |
DEPENDENT UNION |
UNION 中第二个或者后面的 select 语句,依赖于外层的 select |
UNION RESULT |
UNION 的结果 |
SUBQUERY |
子查询的第一个 select |
DEPENDENT SUBQUERY |
子查询的第一个 select,取决于外层的 select |
DERIVED |
派生表 |
MATERIALIZED |
Materialized subquery |
UNCACHEABLE SUBQUERY |
无法缓存结果的子查询,必须为外部查询的每一行重新计算其结果 |
UNCACHEABLE UNION |
UNION 查询中不可缓存的子查询中的第二个或者后一个 select |
- table:输出行对应的表
- partitions:匹配的分区
- type:join 类型
- possible_keys:可选的索引,可以通过 show index from tbl_name 查看表有哪些索引。
- key:实际选择的索引
- key_len:实际使用索引的长度
- ref:与索引比较的列
- rows:扫描行数的预估值
- filtered:按表条件筛选的行的百分比
- Extra:额外信息
3.重点关注的列
3.1 type 列
type 列描述了表的 join 类型,以下以 查询的最优到最差的排序列出了可能值:
- system :当表只有一条数据(= system table)时,为 system 类型,是 const 类型的 特例。
- const:当表最多只有一条数据相匹配时,为 const 类型。因为只有一行,所以优化器的其余部分可以将此行列中的值视为常量(constant)。const表非常快,因为它们只读一次。在使用 主键 或者 唯一索引 和常量比较时,即为 const 类型。
如下的查询,tbl_name 可以被用作 const 表:
SELECT * FROM tbl_name WHERE primary_key=1; SELECT * FROM tbl_name
WHERE primary_key_part1=1 AND primary_key_part2=2;
栗子:
explain select s.* from student s where s.id = 1
输出:
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | SIMPLE | s | NULL | const | PRIMARY | PRIMARY | 8 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
- eq_ref:通常出现在多表 join 查询,并且 关联的字段是 主键 或者 唯一非空索引,即后表 只能匹配一条数据。
下面的示例,可以使用 eq_ref join 来处理 ref_table:
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
- ref:通常出现在多表 join 查询,关联使用了 最左前缀原则的索引 或者 关联的是非主键 或者 非 唯一索引(也就是说,join 不能根据索引选择 单行数据)
下面的示例,Mysql 可以使用 ref join 来处理 ref_table:
SELECT * FROM ref_table WHERE key_column=expr; SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column; SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
- fulltext:使用全文索引执行 join
- ref_or_null:在 ref 的基础上 , 另外还搜索了包含空值的行
下面的示例,Mysql 可以使用 ref_or_null join 来处理 ref_table::
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;
- index_merge: 合并索引优化
- unique_subquery:子查询返回唯一主键。
形如下面的示例:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
- index_subquery:和 unique_subquery 类似,只不过在子查询中使用非唯一索引
形如下面的形式:
value IN (SELECT key_column FROM single_table WHERE some_expr)
- range:当 索引和常量 使用 诸如=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN() 进行比较时 ,可以使用 range.
例如:
SELECT * FROM tbl_name
WHERE key_column = 10; SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20; SELECT * FROM tbl_name
WHERE key_column IN (10,20,30); SELECT * FROM tbl_name
WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
- index:和 all 类似 ,只不过 扫描的是 索引树
- all:全表扫描,可以通过增加 索引避免 全表扫描
3.2 keys 列:真正使用的索引
3.3 rows 列:扫描的记录数
4.使用 explain 提升查询性能案例分析
假设有如下的 sql:根据订单日期 和 店员id 查询 订单信息(已创建了订单日期的索引),查询结果返回 18条记录。
SELECT * FROM orders
WHERE YEAR(o_orderdate) = 1992 AND MONTH(o_orderdate) = 4
AND o_clerk LIKE '%0223';
Explain 输出执行计划:

问题所在:
- 根据 type 为 ALL , 查询进行了全表扫描,被扫描的记录 rows 为 150万。
- possible_keys 和 ky 均为空 ,订单日期索引完全失效,原因在于被索引的字段使用了处理函数导致索引失效
4.1.修改sql 保证 订单日期索引正常,
SELECT * FROM orders
WHERE o_orderdate BETWEEN '1992-04-01' AND '1992-04-30'
AND o_clerk LIKE '%0223';
重新使用 Explain 查看 执行计划:

发现:type 由 ALL 变为 range ,订单日期索引得以利用,被扫描的记录由 15万 降为 3.3万左右。
4.2.另一个优化点在 店员字段的过滤
为 店员字段创建索引:
CREATE INDEX i_o_clerk ON orders(o_clerk);
再次输出执行计划:

发现:基本上并没有什么变化,新建的索引没有被利用,原因在于 该字段是 模糊查询,过滤指定后缀的 店员信息。但是索引对于后缀过滤会失效(尽管索引对于前缀有效果)。
修改sql,全量过滤店员字段:
SELECT * FROM orders
WHERE o_orderdate BETWEEN '1992-04-01' AND '1992-04-30'
AND o_clerk LIKE 'Clerk#000000223';
再次输出执行计划:

发现:可用索引增加,真正使用的索引变为 店员字段上的索引,被扫描的行由 3.3万降为 1546。
4.3.对于多条件查询,可以考虑使用组合索引
创建如下索引:
CREATE INDEX io_clerk_date ON orders(o_clerk, o_orderdate)
** :这里将 o_clerk 放在 o_orderdate 之前,因为 o_orderdate 使用了 范围,更优的放在前面。
再次输出执行计划:

发现:使用了组合索引,被扫描记录即为输出的18条记录。效率已最优化。
多次优化的总结:
| Type | Possible keys | Key | Rows Scanned | Duration (seconds) | Extra info | Rows returned |
|---|---|---|---|---|---|---|
| all | NULL | NULL | 1.50M | 1.201 | Using where | 18 |
| range | i_o_orderdate | i_o_orderdate | 32642 | 0.281 | Using index condition; Using where | 18 |
| range | i_o_orderdate, i_o_clerk | i_o_clerk | 1546 | 0.234 | Using index condition; Using where | 18 |
| range | i_o_orderdate, i_o_clerk, i_o_clerk_date | i_o_clerk_date | 18 | 0.234 | Using index condition | 18 |
【mysql】mysql 调优之 ——执行计划 explain的更多相关文章
- 数据库SQL调优之"执行计划"【未完待续】
什么是“执行计划”?“执行计划”怎么用于SQL调优? 内容待添加... 参考文章: [1]写SQL要学会使用"执行计划" by 鹏霄万里展雄飞
- SQL Server 性能调优 之执行计划(Execution Plan)调优
SQL Server 存在三种 Join 策略:Hash Join,Merge Join,Nested Loop Join. Hash Join:用来处理没有排过序/没有索引的数据,它在内存中把 Jo ...
- MySQL 执行计划explain详解
MySQL 执行计划explain详解 2015-08-10 13:56:27 分类: MySQL explain命令是查看查询优化器如何决定执行查询的主要方法.这个功能有局限性,并不总会说出真相,但 ...
- mysql性能调优与架构设计笔记
1.mysql基本介绍 mysql支持多线程高并发的关系型数据库; 数据库存储引擎InnoDB.MyISAM; mysql快速崛起的原因就是他是开源的; 性能一直是mysql自豪的一大特点; 2.my ...
- MySQL性能优化总结___本文乃《MySQL性能调优与架构设计》读书笔记!
一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...
- MySQL性能调优与架构设计——第9章 MySQL数据库Schema设计的性能优化
第9章 MySQL数据库Schema设计的性能优化 前言: 很多人都认为性能是在通过编写代码(程序代码或者是数据库代码)的过程中优化出来的,其实这是一个非常大的误区.真正影响性能最大的部分是在设计中就 ...
- mysql之调优概论
一 简介 咱们先不说cpu的频率,内存的大小(这个和索引一样重要,但不是本文讨论的内容),硬盘的寻道时间.想起mysql的调优,最起码的必须知道explain执行计划,慢sql日志,老旧的profi ...
- MySQL性能调优思路
1.MySQL性能调优思路 如果一台服务器出现长时间负载过高 /周期性负载过大,或偶尔卡住如何来处理? 是周期性的变化还是偶尔问题?是服务器整体性能的问题, 还是某单条语句的问题? 具体到单条语句, ...
- MySQL性能调优与架构设计——第8章 MySQL数据库Query的优化
第8章 MySQL数据库Query的优化 前言: 在之前“影响 MySQL 应用系统性能的相关因素”一章中我们就已经分析过了Query语句对数据库性能的影响非常大,所以本章将专门针对 MySQL 的 ...
随机推荐
- ubuntu安装时系统分区设置
1. 创建主分区:主分区,用于存放系统 20G 主分区 空间起始位置 Ext4日志文件系统 / 2. 创建swap分区:逻辑分区.大小设置为电脑内存大小,2G: 2048MB ...
- 大数据学习之hdfs集群安装部署04
1-> 集群的准备工作 1)关闭防火墙(进行远程连接) systemctl stop firewalld systemctl -disable firewalld 2)永久修改设置主机名 vi ...
- Android进阶:六、在子线程中直接使用 Toast 及其原理
一般我们都把Toast当做一个UI控件在主线程显示.但是有时候非想在子线程中显示Toast,就会使用Handler切换到主线程显示. 但是子线程中真的不能直接显示Toast吗? 答案是:当然可以. 那 ...
- Android进阶:三、这一次,我们用最详细的方式解析Android消息机制的源码
决定再写一次有关Handler的源码 Handler源码解析 一.创建Handler对象 使用handler最简单的方式:直接new一个Handler的对象 Handler handler = new ...
- BigDecimal.valueOf
Those are two separate questions: "What should I use for BigDecimal?" and "What do I ...
- 其他信息: 未能加载文件或程序集“file:///C:\Program Files (x86)\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Common\SAP BusinessObjects Enterprise XI 4.0\win32_x86\dotnet1\crdb_adoplus.dll”或它的某一个依赖
今天在使用水晶报表的过程中,遇到了这个问题,下面是代码 FormReportView form = new FormReportView(); ReportDocument rptc = new Re ...
- Y1O001波分复用器
# 波分复用器## 光分波器### 波分合波器种类* 耦合型 * 光纤熔融拉锥 * 熔融拉锥法是指将两根(或两根以上)除去涂覆层的光纤以一定的方法靠拢,在高温加热下熔融,同时向两侧拉伸,最终在加热区形 ...
- 思科与华为RIP配置区别
华为配置图如下: 思科配置图如下: 配置原理一样,除了配置命令有点区别:华为进入RIP的命令为:rip 1 思科进入RIP的命令为:router rip
- OI中常犯的傻逼错误总结
OI中常犯的傻逼错误总结 问题 解决方案 文件名出错,包括文件夹,程序文件名,输入输出文件名 复制pdf的名字 没有去掉调试信息 调试时在后面加个显眼的标记 数组开小,超过定义大小,maxn/ ...
- Android四大组件的简介
Android开发四大组件分别是: 一.活动(Activity): 用于表现功能.二.服务(Service): 后台运行服务,不提供界面呈现. 三.广播接收器(BroadcastReceiver):用 ...