mysql最新版explain详解来自官网直译(4)
2017-11-05 17:35
295 查看
EXPLAIN输出的解释说明
通过Explain执行计划输出结果中的值,你能够得到明确的提示,如何才能完成一个好的表连接。也能告诉你大概需要扫描多少行的数据Mysql才能执行完成查询。如果你用max_join_size系统值限定了查询,这行的输出通常被用来决定哪一个multiple-table在查询中被执行和那些被去除。具体请看5.1.1的服务的配置。
接下来的例子说明了一个多表连接的查询是怎么样根据EXPLAIN提供的信息来一步步优化的。
假设你有个如下的查询语句需要处理并且打算执行查询计划:
EXPLAIN SELECT tt.TicketNumber,tt.TimeIn,tt.ProjectReference,tt.EstimatedShipDate,tt.ActualShipDate
,tt.ClientID,tt.ServiceCodes,tt.RepetitiveID, tt.CurrentProcess, tt.CurrentDPPerson, tt.RecordVolume, tt.DPPrinted, et.COUNTRY,et_1.COUNTRY, do.CUSTNAME FROM tt, et, et AS et_1, do
WHERE tt.SubmitTime IS NULL AND tt.ActualPC = et.EMPLOYID AND tt.AssignedPC = et_1.EMPLOYID
AND tt.ClientID = do.CUSTNMBR;
对于该例子,做了如下的假设:
用来比较的列说明如下:
Table Column
Data Type
tt ActualPC
CHAR(10)
tt AssignedPC
CHAR(10)
tt ClientID
CHAR(10)
et EMPLOYID
CHAR(15)
do CUSTNMBR
CHAR(15)
表中的索引如下:
Table Index
tt ActualPC
tt AssignedPC
tt ClientID
et EMPLOYID (primary key)
do CUSTNMBR (primary key)
tt.ActualPC的值不是均匀分布的。
在开始优化之前,执行计划输出的信息如下:
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
do ALL PRIMARY NULL NULL NULL 2135
et_1 ALL PRIMARY NULL NULL NULL 74
tt ALL AssignedPC, NULL NULL NULL 3872
ClientID,
ActualPC
Range checked for each record (index map: 0x23)
因为对于查询中的每张表type类型都是ALL,这样的输出表示mysql对所有的表生成了笛卡尔积;也就是每一行都需要对比。因为在每张表中的数据都需要扫描,所以需要花费好长的时间。从输出的数据中可以看出,这个查询产生了74*2135*74*3872=45268558720行数据。如果表更大一些的话,你可以想象一下查询需要花费多久。
这儿的一个问题是MySQL能够提高效率在列上通过使用索引,如果他们被申明为相同的类型和大小的话。在这里,Varchar和char应该是相同的,如果他们被申明为同样大小。tt.ActualPC的类型为char(10),et.EMPLOYID的类型为char(15),所以他们的长度不匹配。
为了修复这种列长度的不一致,使用ALTER TABLE命令将ActualPC从10char修改为15char
命令:ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
现在tt.ActualPC和et.EMPLOYID的类型都是VARCHAR(15).再次执行EXPLAIN的输出结果如下:
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC, NULL NULL NULL 3872 Using
ClientID, where
ActualPC
do ALL PRIMARY NULL NULL NULL 2135
Range checked for each record (index map: 0x1)
et_1 ALL PRIMARY NULL NULL NULL 74
Range checked for each record (index map: 0x1)
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
这不是完美,但是已经很好了,产生的行数少了74倍,这个版本的执行在几秒内完成。
再来一个修改来排除tt.AssignedPC=et_1.EMPLOYID和tt.ClientID=do.CUSTNMBR比较中的长度不匹配。
命令行为:ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),MODIFY ClientID VARCHAR(15);
执行修改之后,执行计划的输出如下:
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 Using
ClientID, where
ActualPC
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
到这儿,查询几乎没有什么地方可以优化了。依然存在的问题是,默认mysql假设在tt.ActualPC列上的值是均匀分布的,然而实际上tt表不是这样的。很幸运,我们很容易的就告诉mysql去分析key的分布情况。命令如下:
ANALYZE TABLE tt;
通过额外的索引信息,查询采用了完美的连接,EXPLAIN的输出结果如下:
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC NULL NULL NULL 3872 Using
ClientID, where
ActualPC
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
在EXPLAIN中输出的行数是mysql的连接优化器的大致猜想。可以通过核对查询实际输出的行数来对比这个数是否接近于真实。如果数目区别很大,你也许可以通过使用STRAIGHT_JOIN在你的查询中来得到较好的查询效率,再者就是试着用不同的顺序在from之后来提高效率。(然而,STRAIGHT_JOIN会使得已经使用的索引失效,因为它不支持semi-join的事物)。具体请看8.2.2.1的优化子查询,派生表和查看关于Semi-join事物的引用。
还有一些情况下,执行查询可能会修改数据,例如在子查询中使用了EXPLAIN SELECT。更多信息请看13.2.10.8的派生表(在from中的子查询);
到此举例就结束了,接下来我们将要说明的是8.8.3 Extended EXPLAIN Output Format(EXPLAIN输出的扩展)
通过Explain执行计划输出结果中的值,你能够得到明确的提示,如何才能完成一个好的表连接。也能告诉你大概需要扫描多少行的数据Mysql才能执行完成查询。如果你用max_join_size系统值限定了查询,这行的输出通常被用来决定哪一个multiple-table在查询中被执行和那些被去除。具体请看5.1.1的服务的配置。
接下来的例子说明了一个多表连接的查询是怎么样根据EXPLAIN提供的信息来一步步优化的。
假设你有个如下的查询语句需要处理并且打算执行查询计划:
EXPLAIN SELECT tt.TicketNumber,tt.TimeIn,tt.ProjectReference,tt.EstimatedShipDate,tt.ActualShipDate
,tt.ClientID,tt.ServiceCodes,tt.RepetitiveID, tt.CurrentProcess, tt.CurrentDPPerson, tt.RecordVolume, tt.DPPrinted, et.COUNTRY,et_1.COUNTRY, do.CUSTNAME FROM tt, et, et AS et_1, do
WHERE tt.SubmitTime IS NULL AND tt.ActualPC = et.EMPLOYID AND tt.AssignedPC = et_1.EMPLOYID
AND tt.ClientID = do.CUSTNMBR;
对于该例子,做了如下的假设:
用来比较的列说明如下:
Table Column
Data Type
tt ActualPC
CHAR(10)
tt AssignedPC
CHAR(10)
tt ClientID
CHAR(10)
et EMPLOYID
CHAR(15)
do CUSTNMBR
CHAR(15)
表中的索引如下:
Table Index
tt ActualPC
tt AssignedPC
tt ClientID
et EMPLOYID (primary key)
do CUSTNMBR (primary key)
tt.ActualPC的值不是均匀分布的。
在开始优化之前,执行计划输出的信息如下:
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
do ALL PRIMARY NULL NULL NULL 2135
et_1 ALL PRIMARY NULL NULL NULL 74
tt ALL AssignedPC, NULL NULL NULL 3872
ClientID,
ActualPC
Range checked for each record (index map: 0x23)
因为对于查询中的每张表type类型都是ALL,这样的输出表示mysql对所有的表生成了笛卡尔积;也就是每一行都需要对比。因为在每张表中的数据都需要扫描,所以需要花费好长的时间。从输出的数据中可以看出,这个查询产生了74*2135*74*3872=45268558720行数据。如果表更大一些的话,你可以想象一下查询需要花费多久。
这儿的一个问题是MySQL能够提高效率在列上通过使用索引,如果他们被申明为相同的类型和大小的话。在这里,Varchar和char应该是相同的,如果他们被申明为同样大小。tt.ActualPC的类型为char(10),et.EMPLOYID的类型为char(15),所以他们的长度不匹配。
为了修复这种列长度的不一致,使用ALTER TABLE命令将ActualPC从10char修改为15char
命令:ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
现在tt.ActualPC和et.EMPLOYID的类型都是VARCHAR(15).再次执行EXPLAIN的输出结果如下:
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC, NULL NULL NULL 3872 Using
ClientID, where
ActualPC
do ALL PRIMARY NULL NULL NULL 2135
Range checked for each record (index map: 0x1)
et_1 ALL PRIMARY NULL NULL NULL 74
Range checked for each record (index map: 0x1)
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
这不是完美,但是已经很好了,产生的行数少了74倍,这个版本的执行在几秒内完成。
再来一个修改来排除tt.AssignedPC=et_1.EMPLOYID和tt.ClientID=do.CUSTNMBR比较中的长度不匹配。
命令行为:ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),MODIFY ClientID VARCHAR(15);
执行修改之后,执行计划的输出如下:
table type possible_keys key key_len ref rows Extra
et ALL PRIMARY NULL NULL NULL 74
tt ref AssignedPC, ActualPC 15 et.EMPLOYID 52 Using
ClientID, where
ActualPC
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
到这儿,查询几乎没有什么地方可以优化了。依然存在的问题是,默认mysql假设在tt.ActualPC列上的值是均匀分布的,然而实际上tt表不是这样的。很幸运,我们很容易的就告诉mysql去分析key的分布情况。命令如下:
ANALYZE TABLE tt;
通过额外的索引信息,查询采用了完美的连接,EXPLAIN的输出结果如下:
table type possible_keys key key_len ref rows Extra
tt ALL AssignedPC NULL NULL NULL 3872 Using
ClientID, where
ActualPC
et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1
et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
在EXPLAIN中输出的行数是mysql的连接优化器的大致猜想。可以通过核对查询实际输出的行数来对比这个数是否接近于真实。如果数目区别很大,你也许可以通过使用STRAIGHT_JOIN在你的查询中来得到较好的查询效率,再者就是试着用不同的顺序在from之后来提高效率。(然而,STRAIGHT_JOIN会使得已经使用的索引失效,因为它不支持semi-join的事物)。具体请看8.2.2.1的优化子查询,派生表和查看关于Semi-join事物的引用。
还有一些情况下,执行查询可能会修改数据,例如在子查询中使用了EXPLAIN SELECT。更多信息请看13.2.10.8的派生表(在from中的子查询);
到此举例就结束了,接下来我们将要说明的是8.8.3 Extended EXPLAIN Output Format(EXPLAIN输出的扩展)
相关文章推荐
- mysql最新版explain详解来自官网直译(1)
- mysql最新版explain详解来自官网直译(5)
- mysql最新版explain详解来自官网直译(3)
- mysql最新版explain详解来自官网直译(2)
- mysql最新版explain详解来自官网直译(6)
- mysql之explain详解(分析索引的最佳使用)
- mysql之explain详解(分析索引的最佳使用)
- MySQL语句explain详解
- 【MySQL笔记】SQL优化利器 - explain命令的输出格式详解
- MySQL 执行计划explain详解
- mysql中 explain使用详解
- 详解MySQL中EXPLAIN解释命令
- 详解MySQL中EXPLAIN解释命令(转)
- 详解MySQL中EXPLAIN解释命令
- 详解MySQL中EXPLAIN解释命令
- MYSQL语句调优:MYSQL Explain 执行计划输出详解
- 详解MySQL中EXPLAIN解释命令
- 详解MySQL中EXPLAIN解释命令
- MySQL中EXPLAIN解释命令详解
- mysql explain执行计划详解