在mysql数据库中为我们提供了explain方法可以通过它来帮助我们分析我们的sql语句。
登录mysql后,具体使用如下这里的了例子都以上篇博客中安装的实例数据库sakila为例:
explain select * from customer;
通过执行结果,我们看到了explain执行后所包括的内容。每一项代表的具体含义如下:
更加详细的参数及使用说明请参见:
mysql explain用法和结果的含义
select_type:select语句的类型,主要包括
SIMPLE:简单SELECT(不使用UNION或子查询)
PRIMARY:最外面的SELECT
UNION:UNION中的第二个或后面的SELECT语句
DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT:UNION 的结果
SUBQUERY:子查询中的第一个SELECT
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
DERIVED:导出表的SELECT(FROM子句的子查询)
table:查询的表
possible_keys:指出MySQL能使用哪个索引在该表中找到行
key:显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL
key_len:使用索引的长度
type:联接类型。这个参数很重要。下面给出比较常用的几种连接类型:
const:常数查找,如:主键,唯一索引,会很快,因为它们只读取一次!
eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。
ref:基于连接的查找
range:基于索引的范围查找
index:基于索引的扫描。该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
ALL:对于每个来自于先前的表的行组合,进行完整的表扫描。
rows: :扫描的行
extra :该列包含MySQL解决查询的详细信息,这个参数也很重要,主要情况有:
Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
Using filesort:文件排序,需要利用额外的空间。
Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
Using temporary:需要用临时表来容纳结果。
Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,
可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。
注意:
当我们的执行计划所执行的结果的extra中如果出现Using temporary或者Using filesort时,这说明我们的sql语句就需要进行优化了。
对于Using temporary,大家并不陌生,当我们的查询涉及多张表时,需要将查询结果放入第三张临时表中来存放。这样势必会降低我们的查询效率,
所以当遇到extra中为Using temporary时,也许就是我们应该优化的时候了。
但针对于filesort这种情况,我们就没有temporary熟悉了。它究竟是什么情况下发生的呢?
这个 filesort 并不是说通过磁盘文件进行排序,而只是告诉我们进行了一个排序操作。即在MySQL Query Optimizer 所给出的执行计划
(通过 EXPLAIN 命令查看)中被称为文件排序(filesort)
文件排序是通过相应的排序算法,将取得的数据在内存中进行排序: MySQL需要将数据在内存中进行排序,
所使用的内存区域也就是我们通过sort_buffer_size 系统变量所设置的排序区。
这个排序区是每个Thread 独享的,所以说可能在同一时刻在MySQL 中可能存在多个
sort buffer 内存区域。
在MySQL中filesort 的实现算法实际上是有两种:
双路排序:是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在sort buffer 中进行排序。
单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序。
在MySQL4.1版本之前只有第一种排序算法双路排序,第二种算法是从MySQL4.1开始的改进算法,
主要目的是为了减少第一次算法中需要两次访问表数
据的 IO 操作,将两次变成了一次,但相应也会耗用更多的sortbuffer 空间。
当然,MySQL4.1开始的以后所有版本同时也支持第一种算法,
MySQL主要通过比较我们所设定的系统参数 max_length_for_sort_data的大小和Query 语句所取出的字段类型大小总和来判定需要使用哪一种排序算法。
如果 max_length_for_sort_data更大,则使用第二种优化后的算法,反之使用第一种算法。所以如果希望 ORDER BY 操作的效率尽可能的高,
一定要主义max_length_for_sort_data 参数的设置。曾经就有同事的数据库出现大量的排序等待,造成系统负载很高,而且响应时间变得很长,
最后查出正是因为MySQL 使用了传统的第一种排序算法而导致,在加大了max_length_for_sort_data 参数值之后,
系统负载马上得到了大的缓解,响应也快了很多。
当无法避免排序操作时,又该如何来优化呢?很显然,应该尽可能让 MySQL 选择使用第二种单路算法来进行排序。
这样可以减少大量的随机IO操作,很大幅度地提高排序工作的效率。
1、加大 max_length_for_sort_data 参数的设置
在 MySQL 中,决定使用老式排序算法还是改进版排序算法是通过参数 max_length_for_ sort_data 来决定的。
当所有返回字段的最大长度小于这个参数值时,
MySQL 就会选择改进后的排序算法,反之,则选择老式的算法。所以,如果有充足的内存让MySQL 存放须要返回的非排序字段,
就可以加大这个参数的值来让 MySQL 选择使用改进版的排序算法。
2.去掉不必要的返回字段
当内存不是很充裕时,不能简单地通过强行加大上面的参数来强迫 MySQL 去使用改进版的排序算法,否则可能会造成 MySQL
不得不将数据分成很多段,
然后进行排序,这样可能会得不偿失。此时就须要去掉不必要的返回字段,让返回结果长度适应 max_length_for_sort_data 参数的限制。
3、增大 sort_buffer_size 参数设置
增大 sort_buffer_size 并不是为了让 MySQL选择改进版的排序算法,而是为了让MySQL尽量减少在排序过程中对须要排序的数据进行分段,
因为分段会造成 MySQL 不得不使用临时表来进行交换排序。
以上就是有关explain执行计划的一个简单的介绍。通过查看sql语句的执行计划,我们可以很容易的分析出sql语句在哪些子句或者哪些列,
返回结果等地方应该进行着重的优化,为我们提高程序性能带来很大的方便!