mysql子查询速度非常慢
我展示了一个涉及多个跟踪表的销售查询。(仅显示部分数据) 此查询需要0.650s。我想在不同的列中添加子查询,我返回按阶段分发的销售的最后状态。比如:mysql子查询速度非常慢,mysql,sql,performance,subquery,Mysql,Sql,Performance,Subquery,我展示了一个涉及多个跟踪表的销售查询。(仅显示部分数据) 此查询需要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 |
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条记录可供出售。要获取销售状态,我认为需要一个子查询(以及每个阶段):
但是这个子查询115.985s延迟!我想知道,因为它需要这么长时间
编辑30-09-13
根据幻想者的评论,我一些大大提高了查询速度的更改:
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显示数据,谢谢 内部查询会对表中的每一行一次又一次地单独运行,从而使查询时间呈指数级增长(记录越多,情况越糟)。这就是为什么在实际应用程序中要小心处理子查询的原因
我建议您对此查询尝试不同的方法(在许多情况下,一些复杂的联接组合可以替代子查询)。如果此查询效果更好,请尝试一下:
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
再次执行它并发布结果
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)
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);