试图优化大型SQL。包括说明输出

时间:2014-05-01 13:30:51

标签: query-optimization

下面是mysql select语句,后跟解释输出。

我尝试过添加我认为合适但没有额外速度的索引。

'explain'输出中有2行突出(id 7和8,行数超过35,000)

我认为sql需要重组,但我不知道如何更改它。任何帮助,将不胜感激。

EXPLAIN     SELECT wo.JobStatusID
       ,wo.JobNo
       ,ql.RackCode
       ,ql.Description
       ,c.CustName
       ,s.ShipDate
       ,s.Qty
       ,pl.PrepLocation
       ,wl.WeldLocation
       ,line.WeldLine
       ,pm.Initials
       ,pqty.ShipTotal
       ,pqty.POTotal
       ,po.POCount
       ,s2.Notes
       ,bm.UnitQty
       ,labour.AssemblyLabour
       ,labour.WeldLabour
       ,labour.TotalGUTLabour + labour.TotalGUTSetUp / pqty.POTotal AS GUTLabour
       ,labour.TotalPrepLabour + labour.TotalPrepSetUp / pqty.POTotal AS PrepLabour
       ,pqty.POTotal
    FROM WorkOrders wo
    JOIN (
           SELECT JobNo
               ,MasterJobNo AS RelevantJobNo
            FROM WorkOrders
            WHERE MasterJobNo != 0
           UNION
           SELECT JobNo
               ,JobNo AS RelevantJobNo
            FROM WorkOrders
            WHERE MasterJobNo = 0
         ) AS r
        ON r.JobNo = wo.JobNo
    LEFT JOIN QuoteLog ql
        ON ql.QuoteID = wo.QuoteID
           AND wo.FOCPlayArea = 0
    LEFT JOIN Customer c
        ON c.CustID = ql.CustID
    LEFT JOIN WOSchedule s
        ON s.JobNo = wo.JobNo
           AND s.ObsoleteInd = 0
    LEFT JOIN (
                SELECT JobNo
                       ,Notes
                    FROM WOSchedule
                    ORDER BY ShipDate DESC
              ) AS s2
        ON s2.JobNo = wo.JobNo
    LEFT JOIN PrepLocation pl
        ON pl.PrepLocationID = wo.PrepLocationID
    LEFT JOIN WeldLocation wl
        ON wl.WeldLocationID = wo.WeldLocationID
    LEFT JOIN ProgramManager pm
        ON pm.ProgramManagerID = wo.ProgramManagerID
    LEFT JOIN (
                SELECT JobNo
                       ,SUM(POQty) AS POTotal
                       ,SUM(ShipQty) AS ShipTotal
                    FROM WOOrderDetails wod
                    JOIN WODetailType wodt
                        ON wodt.DetailTypeID = wod.DetailTypeID
                           AND wodt.ReleaseModeID = 1
                           AND wodt.Inactive = 0
                    WHERE wod.ObsoleteInd = 0
                    GROUP BY wod.JobNo
              ) AS pqty
        ON pqty.JobNo = wo.JobNo
    LEFT JOIN (
                SELECT Jobno
                       ,COUNT(*) AS POCount
                    FROM WOPOs
                    GROUP BY JobNo
              ) AS po
        ON po.JobNo = wo.JobNo
    LEFT JOIN BOMMaterialList bm
        ON bm.JobNo = r.RelevantJobNo
    LEFT JOIN WeldLine line
        ON wo.WeldLineID = line.WeldLineID
    LEFT JOIN (
                SELECT x.JobNo
                       ,x.BOMDetailID
                       ,SUM(x.TotalPrepLabour) AS TotalPrepLabour
                       ,SUM(x.TotalPrepSetUp) AS TotalPrepSetUp
                       ,SUM(x.TotalGUTLabour) AS TotalGUTLabour
                       ,SUM(x.TotalGUTSetUp) AS TotalGUTSetUp
                       ,SUM(x.WeldLabour * x.WeldEfficiency) AS WeldLabour
                       ,SUM(AssemblyLabour * AssemblyEfficiency * UnitQty) AS AssemblyLabour
                    FROM (
                           SELECT bm.JobNo
                               ,bm.BOMDetailID
                               ,bm.UnitQty
                               ,SUM(bm.UnitQty * pl.HitTime * pl.NoHits * pl.NoMen) AS TotalPrepLabour
                               ,SUM(pl.SetUp) AS TotalPrepSetUp
                               ,SUM(bm.UnitQty * gl.HitTime * gl.NoHits * gl.NoMen) AS TotalGUTLabour
                               ,SUM(gl.SetUp) AS TotalGUTSetUp
                               ,bm.WeldLabour
                               ,bm.WeldEfficiency
                               ,bm.AssemblyLabour
                               ,bm.AssemblyEfficiency
                            FROM BOMMaterialList bm
                            LEFT JOIN BOMPrepLabour pl
                                ON pl.BOMDetailID = bm.BOMDetailID
                            LEFT JOIN BOMGUTLabour gl
                                ON gl.BOMDetailID = bm.BOMDetailID
                            GROUP BY BOMDetailID
                         ) AS x
                    GROUP BY x.JobNo
              ) AS labour
        ON bm.BOMDetailID = labour.BOMDetailID
    WHERE ( wo.JobStatusID = 1
            OR wo.JobStatusID = 2
            OR wo.JobStatusID = 3
          )
    GROUP BY wo.JobNo
    ORDER BY wo.JobStatusID
       ,wl.WeldLocation
       ,line.WeldLine
       ,wo.JobNo;



id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    1418    "Using temporary; Using filesort"
1   PRIMARY wo  eq_ref  PRIMARY,IDX_1   PRIMARY 4   r.JobNo 1   "Using where"
1   PRIMARY ql  eq_ref  PRIMARY PRIMARY 4   sbpdf3_custom014.wo.QuoteID 1   
1   PRIMARY c   eq_ref  PRIMARY PRIMARY 2   sbpdf3_custom014.ql.CustID  1   
1   PRIMARY s   ref PRIMARY,IDX_2   PRIMARY 4   r.JobNo 28  
1   PRIMARY <derived4>  ALL NULL    NULL    NULL    NULL    2884    
1   PRIMARY pl  eq_ref  PRIMARY PRIMARY 4   sbpdf3_custom014.wo.PrepLocationID  1   
1   PRIMARY wl  eq_ref  PRIMARY PRIMARY 4   sbpdf3_custom014.wo.WeldLocationID  1   
1   PRIMARY pm  eq_ref  PRIMARY PRIMARY 4   sbpdf3_custom014.wo.ProgramManagerID    1   
1   PRIMARY <derived5>  ALL NULL    NULL    NULL    NULL    1244    
1   PRIMARY <derived6>  ALL NULL    NULL    NULL    NULL    1310    
1   PRIMARY bm  ref IDX1    IDX1    4   r.RelevantJobNo 19  
1   PRIMARY line    ref PRIMARY PRIMARY 4   sbpdf3_custom014.wo.WeldLineID  1   
1   PRIMARY <derived7>  ALL NULL    NULL    NULL    NULL    1102    
7   DERIVED <derived8>  ALL NULL    NULL    NULL    NULL    35736   "Using temporary; Using filesort"
8   DERIVED bm  index   NULL    PRIMARY 4   NULL    35268   
8   DERIVED pl  ref PRIMARY PRIMARY 4   sbpdf3_custom014.bm.BOMDetailID 1   
8   DERIVED gl  ref PRIMARY PRIMARY 4   sbpdf3_custom014.bm.BOMDetailID 1   
6   DERIVED WOPOs   index   NULL    IDX_1   4   NULL    1804    "Using index"
5   DERIVED wod ref IDX_1   IDX_1   1       1660    "Using where; Using temporary; Using filesort"
5   DERIVED wodt    eq_ref  PRIMARY PRIMARY 2   sbpdf3_custom014.wod.DetailTypeID   1   "Using where"
4   DERIVED WOSchedule  ALL NULL    NULL    NULL    NULL    2884    "Using filesort"
2   DERIVED WorkOrders  range   IDX_2   IDX_2   4   NULL    15  "Using where; Using index"
3   UNION   WorkOrders  ref IDX_2   IDX_2   4       689 "Using index"
NULL    "UNION RESULT"  <union2,3>  ALL NULL    NULL    NULL    NULL    NULL

1 个答案:

答案 0 :(得分:2)

这里有很多东西要看,但我确实发现了这个子查询:

  SELECT JobNo
       ,MasterJobNo AS RelevantJobNo
    FROM WorkOrders
    WHERE MasterJobNo != 0
   UNION
   SELECT JobNo
       ,JobNo AS RelevantJobNo
    FROM WorkOrders
    WHERE MasterJobNo = 0

我认为可以像这样重写:

      SELECT JobNo
           ,CASE WHEN MasterJobNo != 0 
                THEN MasterJobNo 
                ELSE JobNo END AS RelevantJobNo
       FROM WorkOrders

一旦我们以这种方式重写它,我们想知道它为什么需要成为子查询,而不是简单地加入表。然后我再看一遍,看到我们已经在查询中使用了这个表,因此我们可以完全消除该连接,并将CASE表达式包含在适当的位置。此外,此表达式仅用于我可以发现的一个位置(连接到BOMMaterialList)。

我也注意到了这个子查询:

SELECT JobNo
       ,Notes
FROM WOSchedule
ORDER BY ShipDate DESC

我认为我们也可以消除这种情况。当用作派生表时,没有LIMIT的ORDER BY在此处没有任何意义,并且:此表已经包含在另一个地方的查询中。提供此s2子查询和先前s表的数据之间的唯一区别是对ObsoleteInd字段的检查,s2中唯一使用的地方数据是{{1 select子句中的字段。 Notes表仅用于ShipDate和Qty项的选择列表。

所以我可以告诉我们,这应该会有所改善:

s

可能还有一些其他改进可能,但我怀疑大多数改进都来自检查您的索引使用。