0

0

MySQL优化—工欲善其事,必先利其器之EXPLAIN_MySQL

php中文网

php中文网

发布时间:2016-06-01 13:27:10

|

1365人浏览过

|

来源于php中文网

原创

MySQLexplain

bitsCN.com

最近慢慢接触mysql,了解如何优化它也迫在眉睫了,话说工欲善其事,必先利其器。最近我就打算了解下几个优化mysql中经常用到的工具。今天就简单介绍下explain。

环境准备

MySQL版本:

创建测试表

CREATE TABLE people(    id bigint auto_increment primary key,    zipcode char(32) not null default '',    address varchar(128) not null default '',    lastname char(64) not null default '',    firstname char(64) not null default '',    birthdate char(10) not null default '');CREATE TABLE people_car(    people_id bigint,    plate_number varchar(16) not null default '',    engine_number varchar(16) not null default '',    lasttime timestamp);

插入测试数据

insert into people(zipcode,address,lastname,firstname,birthdate)values('230031','anhui','zhan','jindong','1989-09-15'),('100000','beijing','zhang','san','1987-03-11'),('200000','shanghai','wang','wu','1988-08-25')insert into people_car(people_id,plate_number,engine_number,lasttime)values(1,'A121311','12121313','2013-11-23 :21:12:21'),(2,'B121311','1S121313','2011-11-23 :21:12:21'),(3,'C121311','1211SAS1','2012-11-23 :21:12:21')

创建索引用来测试

alter table people add key(zipcode,firstname,lastname);

 

EXPLAIN 介绍

 先从一个最简单的查询开始:

Query-1explain select zipcode,firstname,lastname from people;

EXPLAIN输出结果共有id,select_type,table,type,possible_keys,key,key_len,ref,rows和Extra几列。

id

Query-2explain select zipcode from (select * from people a) b;

id是用来顺序标识整个查询中SELELCT 语句的,通过上面这个简单的嵌套查询可以看到id越大的语句越先执行。该值可能为NULL,如果这一行用来说明的是其他行的联合结果,比如UNION语句:

Query-3explain select * from people where zipcode = 100000 union select * from people where zipcode = 200000;

 

select_type

SELECT语句的类型,可以有下面几种。

SIMPLE

最简单的SELECT查询,没有使用UNION或子查询。见Query-1。

 

PRIMARY

在嵌套的查询中是最外层的SELECT语句,在UNION查询中是最前面的SELECT语句。见Query-2和Query-3。

 

UNION

UNION中第二个以及后面的SELECT语句。 见Query-3。

 

DERIVED

派生表SELECT语句中FROM子句中的SELECT语句。见Query-2。

 

UNION RESULT

一个UNION查询的结果。见Query-3。

 

DEPENDENT UNION

顾名思义,首先需要满足UNION的条件,及UNION中第二个以及后面的SELECT语句,同时该语句依赖外部的查询。

Query-4explain select * from people where id in  (select id from people where zipcode = 100000 union select id from people where zipcode = 200000 );

Query-4中select id from people where zipcode = 200000的select_type为DEPENDENT UNION。你也许很奇怪这条语句并没有依赖外部的查询啊。

这里顺带说下MySQL优化器对IN操作符的优化,优化器会将IN中的uncorrelated subquery优化成一个correlated subquery(关于correlated subquery参见这里)。

SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);

类似这样的语句会被重写成这样:

SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);

所以Query-4实际上被重写成这样:

Query-5explain select * from people o where exists  (select id from people where zipcode = 100000 and id = o.id union select id from people where zipcode = 200000  and id = o.id);

 

SUBQUERY

子查询中第一个SELECT语句。

Query-6explain select * from people  where id =  (select id from people where zipcode = 100000);

 

DEPENDENT SUBQUERY

和DEPENDENT UNION相对UNION一样。见Query-5。

除了上述几种常见的select_type之外还有一些其他的这里就不一一介绍了,不同MySQL版本也不尽相同。

 

table

显示的这一行信息是关于哪一张表的。有时候并不是真正的表名。

Query-7explain select * from (select * from (select * from people a) b ) c;

可以看到如果指定了别名就显示的别名。

N>N就是id值,指该id值对应的那一步操作的结果。

还有M,N>这种类型,出现在UNION语句中,见Query-4。

 

type

type列很重要,是用来说明表与表之间是如何进行关联操作的,有没有使用索引,主要有下面几种类别。

const

当确定最多只会有一行匹配的时候,MySQL优化器会在查询前读取它而且只读取一次,因此非常快。const只会用在将常量和主键或唯一索引进行比较时,而且是比较所有的索引字段。people表在id上有一个主键索引,在(zipcode,firstname,lastname)有一个二级索引。因此Query-8的type是const而Query-9并不是:

Query-8explain select * from people where id=1;

Query-9explain select * from people where zipcode = 100000;

注意下面的Query-10也不能使用const table,虽然也是主键,也只会返回一条结果。

Query-10explain select * from people where id >2;

 

system

这是const连接类型的一种特例,表仅有一行满足条件。

Query-11explain select * from (select * from people where id = 1 )b;

已经是一个const table并且只有一条记录。

 

eq_ref

eq_ref类型是除了const外最好的连接类型,它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。

需要注意InnoDB和MyISAM引擎在这一点上有点差别。InnoDB当数据量比较小的情况type会是All。我们上面创建的people 和 people_car默认都是InnoDB表。

Query-12explain select * from people a,people_car b where a.id = b.people_id;

 

我们创建两个MyISAM表people2和people_car2试试:

CREATE TABLE people2(    id bigint auto_increment primary key,    zipcode char(32) not null default '',    address varchar(128) not null default '',    lastname char(64) not null default '',    firstname char(64) not null default '',    birthdate char(10) not null default '')ENGINE = MyISAM;CREATE TABLE people_car2(    people_id bigint,    plate_number varchar(16) not null default '',    engine_number varchar(16) not null default '',    lasttime timestamp)ENGINE = MyISAM;
Query-13explain select * from people2 a,people_car2 b where a.id = b.people_id;

我想这是InnoDB对性能权衡的一个结果。

eq_ref可以用于使用 = 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。如果关联所用的索引刚好又是主键,那么就会变成更优的const了:

Query-14explain select * from people2 a,people_car2 b where a.id = b.people_id and b.people_id = 1;

 

ref

AlibabaWOOD
AlibabaWOOD

阿里巴巴打造的多元电商视频智能创作平台

下载

这个类型跟eq_ref不同的是,它用在关联操作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。ref可以用于使用=或操作符的带索引的列。

为了说明我们重新建立上面的people2和people_car2表,仍然使用MyISAM但是不给id指定primary key。然后我们分别给id和people_id建立非唯一索引。

reate index people_id on people2(id);create index people_id on people_car2(people_id);

然后再执行下面的查询:

Query-15explain select * from people2 a,people_car2 b where a.id = b.people_id and a.id > 2;

Query-16explain select * from people2 a,people_car2 b where a.id = b.people_id and a.id = 2;

Query-17explain select * from people2 a,people_car2 b where a.id = b.people_id;

Query-18explain select * from people2 where id = 1;

看上面的Query-15,Query-16和Query-17,Query-18我们发现MyISAM在ref类型上的处理也是有不同策略的。

对于ref类型,在InnoDB上面执行上面三条语句结果完全一致。

 

fulltext

链接是使用全文索引进行的。一般我们用到的索引都是B树,这里就不举例说明了。

 

ref_or_null

该类型和ref类似。但是MySQL会做一个额外的搜索包含NULL列的操作。在解决子查询中经常使用该联接类型的优化。(详见这里)。

Query-19mysql> explain select * from people2 where id = 2 or id is null;

Query-20explain select * from people2 where id = 2 or id is not null;

注意Query-20使用的并不是ref_or_null,而且InnnoDB这次表现又不相同(数据量大的情况下有待验证)。

 

index_merger

该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。关于索引合并优化看这里。

 

unique_subquery

该类型替换了下面形式的IN子查询的ref:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。

 

index_subquery

该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

 

range

只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、、>、>=、、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range:

Query-21explain select * from people where id = 1 or id = 2;


注意在我的测试中:发现只有id是主键或唯一索引时type才会为range。

 

index

该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。这个类型通常的作用是告诉我们查询是否使用索引进行排序操作。

Query-22explain select * from people order by id;

至于什么情况下MySQL会利用索引进行排序,等有时间再仔细研究。最典型的就是order by后面跟的是主键。

 

ALL

最慢的一种方式,即全表扫描。

 

总的来说:上面几种连接类型的性能是依次递减的(system>const),不同的MySQL版本、不同的存储引擎甚至不同的数据量表现都可能不一样。

 

possible_keys

possible_keys列指出MySQL能使用哪个索引在该表中找到行。

 

key

key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

 

key_len

key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好 。

 

ref

ref列显示使用哪个列或常数与key一起从表中选择行。

 

rows

rows列显示MySQL认为它执行查询时必须检查的行数。

 

Extra

Extra是EXPLAIN输出中另外一个很重要的列,该列显示MySQL在查询过程中的一些详细信息,包含的信息很多,只选择几个重点的介绍下。

Using filesort 

MySQL有两种方式可以生成有序的结果,通过排序操作或者使用索引,当Extra中出现了Using filesort 说明MySQL使用了后者,但注意虽然叫filesort但并不是说明就是用了文件来进行排序,只要可能排序都是在内存里完成的。大部分情况下利用索引排序更快,所以一般这时也要考虑优化查询了。

 

Using temporary

说明使用了临时表,一般看到它说明查询需要优化了,就算避免不了临时表的使用也要尽量避免硬盘临时表的使用。

 

Not exists

MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行, 就不再搜索了。

 

Using index 

说明查询是覆盖了索引的,这是好事情。

 

Using index condition

这是MySQL 5.6出来的新特性,叫做“索引条件推送”。简单说一点就是MySQL原来在索引上是不能执行如like这样的操作的,但是现在可以了,这样减少了不必要的IO操作,但是只能用在二级索引上,详情点这里。

 

Ok,EXPLAIN了解就到这里,其实这些内容网上都有,只是自己实际操练下会印象更深刻。下一节会介绍SHOW PROFILE。

 

bitsCN.com

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
全国统一发票查询平台入口合集
全国统一发票查询平台入口合集

本专题整合了全国统一发票查询入口地址合集,阅读专题下面的文章了解更多详细入口。

19

2026.02.03

短剧入口地址汇总
短剧入口地址汇总

本专题整合了短剧app推荐平台,阅读专题下面的文章了解更多详细入口。

27

2026.02.03

植物大战僵尸版本入口地址汇总
植物大战僵尸版本入口地址汇总

本专题整合了植物大战僵尸版本入口地址汇总,前往文章中寻找想要的答案。

15

2026.02.03

c语言中/相关合集
c语言中/相关合集

本专题整合了c语言中/的用法、含义解释。阅读专题下面的文章了解更多详细内容。

3

2026.02.03

漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题
漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题

本专题围绕漫蛙漫画(Manwa / Manwa2)官网网页版入口进行整理,涵盖漫蛙漫画官方主页访问方式、网页版在线阅读入口、台版正版漫画浏览说明及基础使用指引,帮助用户快速进入漫蛙漫画官网,稳定在线阅读正版漫画内容,避免误入非官方页面。

13

2026.02.03

Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口
Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口

本专题汇总了俄罗斯知名搜索引擎 Yandex 的官网入口、免登录访问地址、中文登录方法与网页版使用指南,帮助用户稳定访问 Yandex 官网,并提供一站式入口汇总。无论是登录入口还是在线搜索,用户都能快速获取最新稳定的访问链接与使用指南。

114

2026.02.03

Java 设计模式与重构实践
Java 设计模式与重构实践

本专题专注讲解 Java 中常用的设计模式,包括单例模式、工厂模式、观察者模式、策略模式等,并结合代码重构实践,帮助学习者掌握 如何运用设计模式优化代码结构,提高代码的可读性、可维护性和扩展性。通过具体示例,展示设计模式如何解决实际开发中的复杂问题。

3

2026.02.03

C# 并发与异步编程
C# 并发与异步编程

本专题系统讲解 C# 异步编程与并发控制,重点介绍 async 和 await 关键字、Task 类、线程池管理、并发数据结构、死锁与线程安全问题。通过多个实战项目,帮助学习者掌握 如何在 C# 中编写高效的异步代码,提升应用的并发性能与响应速度。

2

2026.02.03

Python 强化学习与深度Q网络(DQN)
Python 强化学习与深度Q网络(DQN)

本专题深入讲解 Python 在强化学习(Reinforcement Learning)中的应用,重点介绍 深度Q网络(DQN) 及其实现方法,涵盖 Q-learning 算法、深度学习与神经网络的结合、环境模拟与奖励机制设计、探索与利用的平衡等。通过构建一个简单的游戏AI,帮助学习者掌握 如何使用 Python 训练智能体在动态环境中作出决策。

3

2026.02.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML教程
HTML教程

共500课时 | 5.3万人学习

php初学者入门课程
php初学者入门课程

共10课时 | 0.6万人学习

RunnerGo从入门到精通
RunnerGo从入门到精通

共22课时 | 1.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号