2013-09-28 94 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的一些复杂的组合可以代替子查询)。