2016-12-29 54 views
0

我在前一週有一個類似的問題,那就是一直在運行的查詢。在編寫這個查詢時,我嘗試應用從另一個查詢中學到的一些東西,但是執行需要很長的時間。查詢優化/修復

當運行查詢的兩個單獨部分時,每個部分需要2分鐘才能完成,儘管速度會更快。

這是我的查詢:

SELECT 
    x.entityCode 'Entity Code' 
, x.nnd_volume 'Latest Brand Volume' 
, maxDate   'Last Action Date' 
, x.Brand   'Brand Description' 
, (SELECT 
      ROUND(((SELECT (MAX(A.line_value * B.pack_volume)) 
         FROM master_data.brand_master B 
         WHERE A.brand_code = B.brand_code 
          AND A.brand_code = B.brand_code) 
       /--THIS IS NOT A BUG, JUST TRYING TO CLEARLY INDICATE THE TWO SELECTS BEING DIVIDED AND CALCULATED 
        (SELECT C.case_volume 
         FROM master_data.brand_master C 
         WHERE A.brand_code = C.brand_code 
          AND A.brand_code = C.brand_code)),2) 'brand_volume' 
     FROM am_lines.brand_module A 
     WHERE A.action_date BETWEEN DATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY)) 
     AND DATE(DATE_SUB(CURDATE(), INTERVAL 0 DAY)) 
     AND A.entity_code = x.entityCode 
     AND A.brand_code = x.brandCode 
     GROUP BY A.entity_code, A.brand 
    ) 'Max Brand (28 Days)' 
FROM 
    (SELECT 
     BBM.entity_code AS entityCode  
    , MAX(action_date) AS maxDate 
    , brand AS Brand 
    , brand_code AS brandCode 
    , ROUND(((SELECT (BBM.line_value * B.pack_volume) 
     FROM master_data.brand_master B 
     WHERE BBM.brand_code = B.brand_code AND BBM.brand_code = B.brand_code) 
    /--THIS IS NOT A BUG, JUST TRYING TO CLEARLY INDICATE THE TWO SELECTS BEING DIVIDED AND CALCULATED 
    (SELECT C.box_volume 
     FROM master_data.brand_master C 
     WHERE BBM.brand_code = C.brand_code AND BBM.brand_code = C.brand_code)),2) 'brand_volume' 
    FROM 
     am_lines.brand_module BBM 
    WHERE 
     line_field_id IN (3154, 3655) 
    AND action_date BETWEEN DATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY)) AND DATE(DATE_SUB(CURDATE(), INTERVAL 0 DAY))  
    GROUP BY 
    -- action_date 
     entity_code 
    , brand_code) AS X 
GROUP BY 
    x.entityCode 
, x.brand;  

樣本數據(該包卷和Box體積僅僅是一個參考表,該表指示總單元在電池組/盒,並用於計算,因此我也沒有在採樣數據)包括它:

entity_code | action_date| brand | line_value 
    ------------+------------+----------+----------- 
    108792  |2016-12-07 |brand 001 | 25 
    108793  |2016-12-08 |brand 002 | 36 
    108795  |2016-12-06 |brand 003 | 10 
    108796  |2016-12-05 |brand 004 | 55 
    108795  |2016-12-13 |brand 001 | 5 
    108792  |2016-12-14 |brand 003 | 2 
    108793  |2016-12-14 |brand 005 | 15 
    108796  |2016-12-16 |brand 006 | 25 

CURRENT成果這一工作:

  • 每個選擇曲在幾分鐘內運行(最多2個)並給出期望的結果 。
  • action_date和line_field_id被編入索引。
  • 向entity_code添加索引會導致表格放慢,原因不明。

CURRENT問題方面富有經驗/期望的結果:

  • 作爲一個需要永遠運行,在超過2小時 整個查詢運行。
  • 每個實體將出售/持有多個品牌的庫存。我需要確定在28天週期和一個月內持有的MAXIMUM股票(Max Holding 28天柱在期望的集合中)。
  • 我還需要顯示最近一週的股票持有情況(Brand Holding Column In desired set)。

所需的結果集VIEW:

entity_code | Last Date | brand holding | Max Holding (28 Days) |Brand 
    ------------+------------+------------------+-----------------------+----------+ 
    108792  |2016-12-27 |10    | 25     |Brand 001 
    108792  |2016-12-27 |36    | 36     |Brand 002 
    108792  |2016-12-27 |5     | 10     |Brand 003 
    108792  |2016-12-27 |25    | 55     |Brand 004 
    108792  |2016-12-27 |4     | 5     |Brand 005 
    108783  |2016-12-15 |80    | 80     |Brand 001 
    108783  |2016-12-15 |36    | 41     |Brand 002 
    108783  |2016-12-15 |12    | 12     |Brand 003 
    108783  |2016-12-15 |8     | 11     |Brand 004 
    108783  |2016-12-15 |20    | 90     |Brand 005   

查詢計劃(store_code是一樣的實體的代碼,我只是給它改名爲後期的目的): QUERY PLAN (store_code is the same as entity code, I just renamed it for the purpose of the post):

我已經調整我的索引在action_date和line_field_id上。

SHOW CREATE TABLE圖片: enter image description here

+0

品牌模塊表中有幾百萬行。並且在實體代碼上放置一個索引。 –

+0

你能提供給我們一個查詢計劃嗎? – Moudiz

+0

已添加查詢計劃 - 請注意store_code與實體代碼相同。我只是爲了帖子的目的而改變了列名。 –

回答

0

讓我給你一些提示。如果他們還不夠,讓我們重新開始。

  • 你有很多子查詢是不需要的;你會更好的與JOINs
  • CURDATE也沒有時間,所以它不需要轉換爲DATEDATE(DATE_SUB(CURDATE(), INTERVAL 28 DAY)) - >(CURDATE() - INTERVAL 28 DAY)
  • 請使用某種形式的縮進,以幫助區分的子查詢。
  • 什麼保證(SELECT ROUND...只返回一行?也許GROUP BY是多餘的?
  • 有時您使用brand,有時brand_code;這是一個'錯誤'嗎?
  • 添加下面的索引;我無法分辨哪些是最好的。

指標:

INDEX(action_date, entity_code, brand_code) 
INDEX(line_field_id, action_date) 
INDEX(entity_code, brand, action_date) 

附錄

  • 不要使用VARCHAR你需要計算其值,如MAX(A.line_value * B.pack_volume)
  • 請勿在VARCHAR上盲目使用(255),請使用'合理'的最大長度。
  • 在任何InnoDB表上都有PRIMARY KEY
  • 不匹配的類型,如line_field_id IN (3154, 3655)VARCHAR(900)阻止合理的優化和可能產生'錯誤'的結果。

(我不會再考慮這個問題,至少到數據類型「固定」。)

+0

感謝您的反饋。我會嘗試實施一些您建議的更改。我只想問你在哪裏建議我使用JOINS而不是子查詢? 我注意到在我的entity_code上有索引也減慢了我的查詢,所以我改變了(不知道爲什麼會發生這種情況)。 因此,我將索引更改爲line_field_id和action_date。 「 –

+0

」改變了我的索引「 - 我希望你會添加索引,而不是改變一個索引。 –

+0

請提供'SHOW CREATE TABLE'。有了它們,也許我可以猜測如何使用'JOIN'。 –