2013-09-28 92 views
0

我顯示一個涉及多個跟蹤表的銷售查詢。 (僅示出了一些數據)mysql子查詢極其緩慢

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification 
FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
WHERE v.flag = 1 
AND  EXISTS(SELECT '1' 
          FROM sale_history 
          WHERE id_sale = v.id_sale 
          AND flag = 1 
          LIMIT 1) 
AND v.id_headquarters_detail = 2 

這個查詢需要0.650s。我想在不同的列中添加子查詢,我將分階段銷售的最後一個狀態返回。喜歡的東西:

id_sale | ... | last_state_of_stage_1 | last_state_of_stage_2 | last_state_of_stage_3 
01  | ... | new_sale    | distributed_sale  | canceled_sale 
02  | ... | new_sale    | distributed_sale  | invoiced_sale 
... 

的狀態和每個銷售階段都存儲在一個歷史:

sale_history 
------------ 
id_history int -- primary key 
id_sale int 
id_state_detail int -- contains the states id's and logic 
observation tinytext 
date_history datetime 
id_user int 
id_profile int 
... 

指標:

CREATE INDEX indx_id_sale USING BTREE ON sale_history (id_sale); 
CREATE INDEX indx_id_state_detail USING BTREE ON sale_history (id_state_detail); 

每個歷史上,共有25條記錄銷售的平均水平。要做成這筆買賣的狀態,我覺得一個子查詢(以及每個階段的):

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification, 

IFNULL((SELECT state_name 
      FROM sale_history veh 
      INNER JOIN state_detail vec ON vec.id_state_detail = veh.id_state_detail 
      INNER JOIN sale_state ve ON ve.iid_sale_state= vec.iid_sale_state 
      WHERE veh.id_sale = v.id_sale 
      AND vec.iid_sale_stage = 5 
      AND veh.flag = 1 
      ORDER BY veh.id_history DESC 
      LIMIT 1 
),'x') last_state_of_stage_1 

FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
WHERE v.flag = 1 
AND  EXISTS(SELECT '1' 
          FROM sale_history 
          WHERE id_sale = v.id_sale 
          AND flag = 1 
          LIMIT 1) 
AND v.id_headquarters_detail = 2 

但這子查詢115.985s延遲!我想知道,因爲它需要這麼長時間?

編輯30-09-13

通過的FancyPants的意見,我做了一些變化,這大大提高了查詢的速度:

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification, 
    IFNULL(ve5.state_name,'x') last_state_of_stage_1 
FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
LEFT JOIN sale_history veh5 ON veh5.id_sale = v.id_sale AND veh5.flag = 1 AND veh5.id_history = (SELECT MAX(sh.id_history) 
                                                    FROM sale_history sh 
                                                    INNER JOIN state_detail vecx ON vecx.id_state_detail = sh.id_state_detail 
                                                    INNER JOIN sale_state vex ON vex.iid_sale_state= vecx.iid_sale_state 
                                                    WHERE sh.id_sale = v.id_sale AND sh.id_sale = veh5.id_sale 
                                                    AND sh.flag = 1 
                                                    AND vecx.iid_sale_stage = 5 
                                                    ) 
LEFT JOIN state_detail vec5 ON vec5.id_state_detail = veh5.id_state_detail 
LEFT JOIN sale_state ve5 ON ve5.iid_sale_state = vec5.iid_sale_state 
WHERE v.flag = 1 
AND  EXISTS(SELECT '1' 
          FROM sale_history 
          WHERE id_sale = v.id_sale 
          AND flag = 1 
          LIMIT 1) 
AND v.id_headquarters_detail = 2 
AND EXISTS(SELECT '1' 
       FROM sale_activity veh 
       INNER JOIN state_detail vec ON vec.id_state_detail = veh.id_state_detail 
       INNER JOIN sale_state ve ON ve.iid_sale_state= vec.iid_sale_state 
       WHERE id_sale = v.id_sale 
       AND iid_sale_stage = 4 
       LIMIT 1) 

現在採取0.609s到顯示數據,謝謝!

回答

1

請試試如果該查詢工作得更好:

SELECT 
    CONCAT(cam.c_prefix, LPAD(v.id_sale,5,'0')) Code, 
    ve.estate_name last_state, 
    v.date_instalation, 
    va.date_state date_modification, 
    COALESCE(state_name, 'x') last_state_of_stage_1 
FROM sale v 
INNER JOIN headquarters_detail sd ON v.id_headquarters_detail = sd.id_headquarters_detail 
INNER JOIN headquarters se ON sd.id_headquarters = se.id_headquarters 
INNER JOIN campaign cam ON sd.id_campaign = cam.id_campaign 
INNER JOIN sale_activity va ON va.id_sale = v.id_sale 
INNER JOIN state_detail vec ON vec.id_state_detail = va.id_state_detail 
INNER JOIN sale_state ve ON ve.iid_sale_state = vec.iid_sale_state 
INNER JOIN sale_history veh ON veh.id_sale = v.id_sale AND vec.iid_sale_stage = 5 AND veh.flag = 1 
WHERE v.flag = 1 
AND v.id_headquarters_detail = 2 
AND veh.id_history = (SELECT MAX(id_history) FROM sale_history sh WHERE sh.id_sale = veh.id_sale); 

如果它不(假設它產生正確的結果),在它的前面有EXPLAIN再次執行它,併發布結果,請。

+0

謝謝!我編輯了我的問題 – csotelo

1

對於表格的每一行都重複執行內部查詢,指數級地增加查詢時間(更多記錄會變得更糟)。這就是爲什麼子查詢在現實應用中要小心謹慎的原因。

我建議你嘗試不同的方法來查詢(有很多情況下JOIN的一些複雜的組合可以代替子查詢)。