14 优化实例

作者: 笑Skr人啊 | 来源:发表于2017-04-27 11:42 被阅读0次

    本篇例子显示出一个多表JOIN如何能使用EXPLAIN提供的信息逐步被优化。

    假定你有下面所示的SELECT语句,计划使用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;
    
    
    
    • 对于这个例子,假定被比较的列声明如下:
    列类型
    tt ActualPC CHAR(10)
    tt AssignedPC CHAR(10)
    tt ClientID CHAR(10)
    et EMPLOYID CHAR(15)
    do CUSTNMBR CHAR(15)
    • 表有下面的索引:
    索引
    tt ActualPC
    tt AssignedPC
    tt ClientID
    et EMPLOYID(主键)
    do CUSTNMBR(主键)

    -tt.ActualPC值不是均匀分布的。

    table type possible_keys key key_len ref rows
    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,ClientID, ActualPC NULL NULL NULL 3872

    因为type对每张表是ALL,这个输出显示MySQL正在对所有表产生一个笛卡尔乘积;即每一个行的组合!这将花相当长的时间,因为必须检查每张表的行数的乘积!对于一个实例,这是74 * 2135 * 74 * 3872 = 45,268,558,720行。如果表更大,你只能想象它将花多长时间……

    这里的一个问题是MySQL能更高效地在声明具有相同类型和尺寸的列上使用索引。在本文中,VARCHAR和CHAR是相同的,除非它们声明为不同的长度。因为tt.ActualPC被声明为CHAR(10)并且et.EMPLOYID被声明为CHAR(15),长度不匹配。

    为了修正在列长度上的不同,使用ALTER TABLE将ActualPC的长度从10个字符变为15个字符:

    mysql> 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,ClientID, ActualPC NULL NULL NULL 3872 Using where
    do ALL PRIMARY NULL NULL NULL 2135 range checked for each record (key map: 1)
    et_1 ALL PRIMARY NULL NULL NULL 74 range checked for each record (key map: 1)
    et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1 --

    这不是完美的,但是好一些了:rows值的乘积少了一个因子74。这个版本在几秒内执行完。

    第2种方法能消除tt.AssignedPC = et_1.EMPLOYID和tt.ClientID = do.CUSTNMBR比较的列的长度失配问题:

    mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),MODIFY ClientID   VARCHAR(15);
    
    

    EXPLAIN产生的输出显示在下面:

    table type possible_keys key key_len ref rows Extra
    et ALL PRIMARY NULL NULL NULL 74
    tt ref AssignedPC,ClientID, ActualPC ActualPC 15 et.EMPLOYID 52 Using where
    et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1
    do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1

    剩下的问题是,默认情况,MySQL假设在tt.ActualPC列的值是均匀分布的,并且对tt表不是这样。幸好,很容易告诉MySQL来分析关键字分布:

    mysql> ANALYZE TABLE tt;
    

    现在联接是“完美”的了,而且EXPLAIN产生这个结果:

    table type possible_keys key key_len ref rows Extra
    tt ALL AssignedPC ,ClientID, ActualPC NULL NULL NULL 3872 Using where
    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输出的rows列是一个来自MySQL联接优化器的“教育猜测”。你应该检查数字是否接近事实。如果不是,可以通过在SELECT语句里面使用STRAIGHT_JOIN并且试着在FROM子句以不同的次序列出表,可能得到更好的性能。

    相关文章

      网友评论

        本文标题:14 优化实例

        本文链接:https://www.haomeiwen.com/subject/mqpgzttx.html