您的位置:首页 > 数据库 > MySQL

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输出的扩展)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  索引 mysql 优化