MySQL 5.7未使用查询索引但8.0可用,求优化方案
针对MySQL 5.7的查询优化方案
你的核心问题在于:外层WHERE条件作用在UNION生成的临时表上,MySQL 5.7的优化器无法自动将过滤条件下推到T1、T2的子查询中,导致你创建的(type,status)索引完全没机会被使用——而MySQL 8.0优化器支持条件下推,所以能正常利用索引。下面是适配5.7的具体优化方案:
将过滤条件下推到UNION子查询中
把外层的过滤逻辑拆分到两个SELECT语句里,让T1、T2在生成临时表前就完成数据过滤,这样5.7就能识别并使用原表的索引:SELECT * FROM ( SELECT ... FROM T1 WHERE type <> "Used" AND status <> "Closed" UNION SELECT ... FROM T2 WHERE type <> "Used" AND status <> "Closed" ) T_union INNER JOIN T3 ON T_union.t3_id = T3.id INNER JOIN T4 ON T3.t4_id = T4.id INNER JOIN T5 ON T_union.t5_id = T5.id INNER JOIN T6 ON T3.t6_id = T6.id INNER JOIN T7 ON T6.t7_id = T7.id若T1和T2的结果集无重复数据,替换
UNION为UNION ALL,省去额外的去重排序开销,进一步提速。创建覆盖型复合索引
针对子查询的过滤+关联需求,给T1、T2创建包含关联字段的复合索引,让MySQL无需回表即可获取所需数据:CREATE INDEX idx_type_status_assoc ON T1 (type, status, t3_id, t5_id); CREATE INDEX idx_type_status_assoc1 ON T2 (type, status, t3_id, t5_id);这种索引将过滤字段(type、status)放在前面,关联字段(t3_id、t5_id)放在后面,既能满足过滤条件的索引使用,又能覆盖关联所需的数据,大幅减少IO开销。
必要时使用强制索引
若优化器仍未选择使用索引,可在子查询中显式指定强制索引:SELECT ... FROM T1 FORCE INDEX(idx_type_status_assoc) WHERE type <> "Used" AND status <> "Closed"注意:此方法仅作为兜底方案,优先通过前两种方式让优化器自动选择最优路径。
内容的提问来源于stack exchange,提问作者jimmy
相关产品推荐
相关产品推荐

