LEFT JOIN导致SQL查询性能下降百倍,请求原因解析
问题解析与优化方案
核心性能骤降原因
对比两个查询的执行计划,性能差异的关键在于requests表的索引使用逻辑:
- 无LEFT JOIN的Query1:使用了
req_status_id_2联合索引(包含deleted、req_status_id、id),属于覆盖索引扫描(using_index: true)——无需回表读取原表数据,直接从索引中获取所有所需字段,扫描效率极高,因此执行时间仅0.012秒。 - 带LEFT JOIN的Query2:因为需要获取
contract_cat_id用于关联wt_contracts_cats,但req_status_id_2索引中不包含该字段,优化器转而选择**index_merge(索引交集)**策略:同时扫描req_status_id和requests_idx55两个索引取交集,再回表读取contract_cat_id。索引交集的扫描效率远低于单一联合索引,且回表操作额外增加了IO开销,这是性能下降百倍的主因。
注:wt_contracts_cats表使用主键eq_ref访问,本身效率很高,并非性能瓶颈。
优化方案
方案1:创建覆盖关联字段的联合索引
为requests表创建包含过滤条件、关联字段、统计字段的联合索引,让Query2也能实现覆盖索引扫描,彻底避免回表和索引交集操作:
CREATE INDEX requests_idx_deleted_status_cat ON requests (deleted, req_status_id, contract_cat_id, id);
创建后,优化器会自动选择该索引,直接从索引中获取所有需要的字段,性能会接近Query1的水平。
方案2:移除无意义的LEFT JOIN
当前Query2中,LEFT JOIN wt_contracts_cats并未参与过滤或统计逻辑(COUNT的是r.id,LEFT JOIN不会减少requests的记录数)。如果业务上不需要该表的其他字段,直接移除LEFT JOIN即可恢复Query1的高效执行。
方案3:强制使用原联合索引(临时应急)
如果暂时无法创建新索引,可以尝试强制优化器使用req_status_id_2索引,再回表取contract_cat_id,该方式的效率通常优于索引交集:
SELECT COUNT(r.id) FROM requests r FORCE INDEX (req_status_id_2) LEFT JOIN wt_contracts_cats wcc ON r.contract_cat_id = wcc.id WHERE r.deleted = 0 AND r.req_status_id = 'processed';
内容的提问来源于stack exchange,提问作者LVX
相关产品推荐
相关产品推荐

