本文转载自MySQL性能优化最佳实践 - 08 SQL EXPLAIN解析

什么是归并排序?

如果需要排序的数据超过了sort_buffer_size的大小,说明无法在内存中完成排序,就需要写到临时文件中。若排序中产生了临时文件,需要利用归并排序算法保证临时文件中的记录是有序的。归并排序算法是分批将数据放到文件中进行排序,然后逐一按序合并。

简单来说是把在内存中无法直接排序的数据进行分批,每批已排序的结果分别放到文件中。用每个已排序的文件中第一行数据做进行比较,取出最小的值放到最终的合并排序文件中。重复以上操作,直到所有文件文件数据都放到合并排序文件中。

执行计划中Using temporary与using filesort的区别?

Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询。

Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”,Using filesort只能在一张表中进行

示例:

mysql> explain
-> select id from sbtest1
-> union
-> select id from sbtest2
-> order by id;
+----+--------------+------------+-------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+-------+---------------+------+---------+------+--------+---------------------------------+
| 1 | PRIMARY | sbtest1 | index | NULL | k_1 | 4 | NULL | 986400 | Using index |
| 2 | UNION | sbtest2 | index | NULL | k_2 | 4 | NULL | 986400 | Using index |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary; Using filesort |
+----+--------------+------------+-------+---------------+------+---------+------+--------+---------------------------------+
# Using temporary:表示使用临时表,将sbtest1和sbtest2数据放到临时表中
# Using filesort:表示将这个临时表进行排序,因Using filesort只能在一张表中进行,所以需要把数据汇总到临时表中,然后再进行排序

表中只有一条数据,为什么在执行计划中也会有using filesort?(实验测试)

mysql> select * from test;
+----+------+------+
| id | name | dept |
+----+------+------+
| 1 | lyj | dnb |
+----+------+------+ mysql> show create table test\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL DEFAULT '0',
`name` varchar(30) DEFAULT NULL,
`dept` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) mysql> explain select * from test order by name;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | test | ALL | NULL | NULL | NULL | NULL | 1 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

filesort表示MySQL需要进行实际的排序操作,而不能通过索引获得已排序数据。

实际上,只要一条 SQL 语句需要进行排序操作,都会显示“Using filesort”,这并不表示就会有文件排序操作。

explain执行计划包含的信息

id:执行顺序

  • id相同,执行顺序由上至下
  • 子查询id的序号会递增,id值越大优先级越高,越先被执行

select _type:查询类型

  1. SIMPLE:查询中不包含子查询或者UNION
  2. 查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY
  3. 在SELECT或WHERE列表中包含了子查询,该子查询被标记为:SUBQUERY
  4. 在FROM列表中包含的子查询被标记为:DERIVED(衍生)
  5. 若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
  6. 从UNION表获取结果的SELECT被标记为:UNION RESULT

table:表

  • 每个执行步骤执行时引用的表
  • derivedN–有时不是真实的表名字,看到的是derivedN(N是id值,指第几步执行的结果)
  • unionM,N(行记录引用的UNIO连接的多个ID值)

type:搜索类型

表示MySQL在表中找到所需行的方式,又称“访问类型”,常见类型如下:

  • ALL(全表):Full Table Scan,MySQL将遍历全表以找到匹配的行
  • index(索引扫描):Full Index Scan,index与ALL区别为index类型只遍历索引树
  • range(范围扫描):索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询
  • ref(关联/参考):非唯一性索引扫描,返回匹配某个单独值的所有行。常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找
  • eq_ref(等值关联/参考):唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
  • const, system(常量):当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量
  • NULL(空):MySQL在优化过程中分解语句,执行时甚至不用访问表或索引

由上至下,响应时间(RT)由最差到最好,through output不一定

mysql> explain select id,c,pad from sbtest1 where pad='';
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | sbtest1 | ALL | NULL | NULL | NULL | NULL | 986400 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+ mysql> explain select count(*) from sbtest1;
+----+-------------+---------+-------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | sbtest1 | index | NULL | k_1 | 4 | NULL | 986400 | Using index |
+----+-------------+---------+-------+---------------+------+---------+------+--------+-------------+ mysql> explain select id,c,pad from sbtest1 where id between 50 and 100;
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | sbtest1 | range | PRIMARY | PRIMARY | 4 | NULL | 51 | Using where |
+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ mysql> explain select * from test where dept='zb';
+----+-------------+-------+------+----------------+----------------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------+----------------+---------+-------+------+--------------------------+
| 1 | SIMPLE | test | ref | test_dept_name | test_dept_name | 93 | const | 5 | Using where; Using index |
+----+-------------+-------+------+----------------+----------------+---------+-------+------+--------------------------+ mysql> explain select * from (select * from test where id=1) d1;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL |
| 2 | DERIVED | test | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+

possible-keys:可能用到的主键/索引

指出MySQL能使用哪个索引在表中找到行,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

key:实际用到的主键/索引

显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。

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

key_len:key的长度

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。

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

ref:参考(字段的关联)

表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

row:估计结果行数

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

MySQL执行计划的局限

  • EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
  • EXPLAIN不考虑各种Cache
  • EXPLAIN不能显示MySQL在执行查询时所作的优化工作
  • 部分统计信息是估算的,并非精确值(如:对Innodb行数的估算)
  • EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划(5.6.*版本已经可以对update,delete操作做EXPALIN)

MySQL5.6支持OPTIMIZER_TRACE

开启可查看步骤:

# 开启
mysql> show variables like '%trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name | Value |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace | enabled=off,one_line=off |
| optimizer_trace_features | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit | 1 |
| optimizer_trace_max_mem_size | 16384 |
| optimizer_trace_offset | -1 |
+------------------------------+----------------------------------------------------------------------------+ set optimizer_trace='enabled=on';
set optimizer_trace_max_mem_size=1000000;
set end_markers_in_json=on; # 查看
mysql> select * from information_schema.optimizer_trace\G;
*************************** 1. row ***************************
QUERY: explain select id,pad from sbtest1 where id<100
TRACE: {
"steps": [
{
"join_preparation": {
"select#": 1,
"steps": [
{
"expanded_query": "/* select#1 */ select `sbtest1`.`id` AS `id`,`sbtest1`.`pad` AS `pad` from `sbtest1` where (`sbtest1`.`id` < 100)"
}
] /* steps */
} /* join_preparation */
},
{
......

SQL EXPLAIN解析的更多相关文章

  1. 牛客网数据库SQL实战解析(31-40题)

    牛客网SQL刷题地址: https://www.nowcoder.com/ta/sql?page=0 牛客网数据库SQL实战解析(01-10题): https://blog.csdn.net/u010 ...

  2. atitit.java解析sql语言解析器解释器的实现

    atitit.java解析sql语言解析器解释器的实现 1. 解析sql的本质:实现一个4gl dsl编程语言的编译器 1 2. 解析sql的主要的流程,词法分析,而后进行语法分析,语义分析,构建sq ...

  3. SQL 软解析和硬解析详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt329 当客户端进程,将SQL语句通过监听器发送到Oracle时, 会触发一个 ...

  4. sql注入解析

    sql注入解析 sql注入解析(一)基本语法 sql注入解析(二)执行注入 sql注入解析(三)数据库类型 sql注入解析(四)避开过滤

  5. sql语句解析顺序和执行顺序

    sql语句执行顺序1.from子句组装来自不同数据源的数据2.where子句基于指定的条件对记录行进行筛选3.group by子句将数据划分为多个分组4.使用聚集函数进行计算5.使用having子句筛 ...

  6. sql 关键字解析

    sql 关键字解析 关键字 解析 union 注意:每个 SELECT 语句,必须列的数量.顺序相同,列的数据类型相似.即:1. UNION 内部的每个 SELECT 语句必须拥有相同数量的列:2. ...

  7. Oracle SQL 硬解析和子游标

    Oracle SQL 硬解析和子游标 What reasons will be happening sql hard parse and generating new child cursors 在一 ...

  8. Java 实现对Sql语句解析

    原文地址:http://www.cnblogs.com/zcftech/archive/2013/06/10/3131286.html 最近要实现一个简易的数据库系统,除了要考虑如何高效的存储和访问数 ...

  9. mybatis源码学习(四):动态SQL的解析

    之前的一片文章中我们已经了解了MappedStatement中有一个SqlSource字段,而SqlSource又有一个getBoundSql方法来获得BoundSql对象.而BoundSql中的sq ...

随机推荐

  1. ScalikeJDBC,操作mysql数据,API

    ScalikeJDBC,操作mysql数据,API 一.构建maven项目,添加pom.xml依赖 二.resource文件下创建application.conf文件,并配置以下内容 三.操作mysq ...

  2. SANGFOR AC配置AD域单点登录(二)----AD域侧配置及单点登录认证、注销测试

    1.AD域侧配置 1)新建组策略并配置logon登录脚本,以实现用户开机登录域时,自动通过AC认证  AD域服务器"运行"输入gpmc.msc,打开组策略编辑器,如下图. 右建需要 ...

  3. C++隐式推导-auto关键词

    总述 C++中有一个关键字,它不进行显式声明,而进行隐式推导,auto可以在声明变量时根据变量初始值的类型自动为此变量选择匹配的类型.C++语言类似的关键字还有decltype. 如何评价 C++ 1 ...

  4. P2801 教主的魔法 (分块)

    题目传送 长度为\(n(n\le 1000000)\)的数组,\(q(q\le 3000)\) 次操作.修改操作即将某个区间的值增加某个不大于1000的值,查询操作即查询某个区间比C大于等于的数有多少 ...

  5. Codeforces Round #626 (Div. 2) D. Present(位运算)

    题意: 求n个数中两两和的异或. 思路: 逐位考虑,第k位只需考虑0~k-1位,可通过&(2k+1-1)得到一组新数. 将新数排序,当两数和在[2k,2k+1)和[2k+1+2k,2k+2)之 ...

  6. tkinter 实现爬虫的UI界面

    使用python的内置模块tkinter编写了爬取51Ape网站(无损音乐的百度云链接)的UI界面 tkinter入门简单, 但同时在编写的过程中因为文档的缺少很不方便. 下面是UI界面模块的编写,由 ...

  7. 牛客编程巅峰赛S1第5场 - 青铜&白银 A.凯撒密码(字符串)

    题意:给你一个加密的字符串,以及偏移量,求对应的明文. 题解:根据样例,不难看出模板串是:\(0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq ...

  8. Jenkins+ant+Jmeter接口自动化框架搭建

    工具准备 JDK: jdk1.8.0_111 Ant: apache-ant-1.9.9 Jmeter: apache-jmeter-3.1 Jenkins: jenkins-2.7.4 JDK安装 ...

  9. CF1471-C. Strange Birthday Party

    CF1471-C. Strange Birthday Party 题意: 你要举办一场生日派对.派对有\(n\)个人,每个人都有一个数字\(k_i\).超市有\(m\)件礼物,购买每件礼物需要花费\( ...

  10. 新闻类爬虫库:Newspaper

    newspaper库是一个主要用来提取新闻内容及分析的Python爬虫框架.此库适合抓取新闻网页.操作简单易学,即使对完全没了解过爬虫的初学者也非常的友好,简单学习就能轻易上手,除此之外,使用过程你不 ...