mysql最新版explain详解来自官网直译(4)

来源:互联网 发布:淘宝客小猪优惠券 编辑:程序博客网 时间:2024/06/04 19:20
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输出的扩展)
原创粉丝点击