MySQL 5.7中如何调整查询JOIN顺序,避免优化器错误选择?
- 内容介绍
- 文章标签
- 相关推荐
本文共计716个文字,预计阅读时间需要3分钟。
MySQL 5.7 没有JOIN_ORDER、JOIN_PREFIX这类高级HINT,唯一能强制JOIN顺序的手段就是STRAIGHT_JOIN——它不是建议,而是硬性要求优化器按你写的表顺序执行连接。
什么时候必须用 STRAIGHT_JOIN?
典型信号很直接:
-
EXPLAIN显示驱动表type=ALL或Extra里出现Using join buffer,而另一张表明明有高选择性索引(比如主键等值、或WHERE条件后只剩几十行) - 多表 JOIN 中,某个中间结果集明显更小(例如子查询加了
LIMIT 100),但优化器仍把它当被驱动表,导致外层全表扫描 × N - 带
ORDER BY的查询,优化器优先选排序字段索引,却忽略了前置过滤条件能筛掉 99% 数据——这时强制先走过滤索引的表做驱动,反而更快
STRAIGHT_JOIN 怎么写才生效?
语法上它必须紧贴在第一个表名之后,且只对 INNER JOIN 生效(LEFT/RIGHT JOIN 不支持):
SELECT STRAIGHT_JOIN * FROM services b JOIN user a ON a.id = b.user_id WHERE a.tel LIKE '136%' ORDER BY b.CreatedTime DESC LIMIT 10;
注意三点:
- 不是
SELECT * STRAIGHT_JOIN ...,STRAIGHT_JOIN是修饰整个SELECT的关键字,位置固定 - 表别名要一致,否则
EXPLAIN看不到效果;改完立刻用EXPLAIN验证驱动表是否变成你期望的那张 - 如果原语句是
FROM user a JOIN services b,但你想让services先走,就得把services搬到FROM后第一位,并加STRAIGHT_JOIN
为什么不能无脑加 STRAIGHT_JOIN?
它绕过了优化器的成本估算,风险明确:
- 数据分布一变(比如某天
user表突然暴涨十倍),原来的小表变大表,STRAIGHT_JOIN就会把性能拖垮 - 上线前必须用生产等效数据量压测,光看
EXPLAIN的rows预估不准——实际执行时间才是唯一标准 - 它只作用于当前语句,不会影响其他查询;但若大量使用,说明统计信息可能长期不准,该跑
ANALYZE TABLE了
真正关键的不是“怎么加 STRAIGHT_JOIN”,而是先确认优化器为啥选错:查 mysql.innodb_index_stats 看统计信息更新时间,SHOW CREATE TABLE 对比字段类型和校对规则——很多所谓“选错顺序”,其实是隐式转换让索引失效,驱动表根本没得选。
本文共计716个文字,预计阅读时间需要3分钟。
MySQL 5.7 没有JOIN_ORDER、JOIN_PREFIX这类高级HINT,唯一能强制JOIN顺序的手段就是STRAIGHT_JOIN——它不是建议,而是硬性要求优化器按你写的表顺序执行连接。
什么时候必须用 STRAIGHT_JOIN?
典型信号很直接:
-
EXPLAIN显示驱动表type=ALL或Extra里出现Using join buffer,而另一张表明明有高选择性索引(比如主键等值、或WHERE条件后只剩几十行) - 多表 JOIN 中,某个中间结果集明显更小(例如子查询加了
LIMIT 100),但优化器仍把它当被驱动表,导致外层全表扫描 × N - 带
ORDER BY的查询,优化器优先选排序字段索引,却忽略了前置过滤条件能筛掉 99% 数据——这时强制先走过滤索引的表做驱动,反而更快
STRAIGHT_JOIN 怎么写才生效?
语法上它必须紧贴在第一个表名之后,且只对 INNER JOIN 生效(LEFT/RIGHT JOIN 不支持):
SELECT STRAIGHT_JOIN * FROM services b JOIN user a ON a.id = b.user_id WHERE a.tel LIKE '136%' ORDER BY b.CreatedTime DESC LIMIT 10;
注意三点:
- 不是
SELECT * STRAIGHT_JOIN ...,STRAIGHT_JOIN是修饰整个SELECT的关键字,位置固定 - 表别名要一致,否则
EXPLAIN看不到效果;改完立刻用EXPLAIN验证驱动表是否变成你期望的那张 - 如果原语句是
FROM user a JOIN services b,但你想让services先走,就得把services搬到FROM后第一位,并加STRAIGHT_JOIN
为什么不能无脑加 STRAIGHT_JOIN?
它绕过了优化器的成本估算,风险明确:
- 数据分布一变(比如某天
user表突然暴涨十倍),原来的小表变大表,STRAIGHT_JOIN就会把性能拖垮 - 上线前必须用生产等效数据量压测,光看
EXPLAIN的rows预估不准——实际执行时间才是唯一标准 - 它只作用于当前语句,不会影响其他查询;但若大量使用,说明统计信息可能长期不准,该跑
ANALYZE TABLE了
真正关键的不是“怎么加 STRAIGHT_JOIN”,而是先确认优化器为啥选错:查 mysql.innodb_index_stats 看统计信息更新时间,SHOW CREATE TABLE 对比字段类型和校对规则——很多所谓“选错顺序”,其实是隐式转换让索引失效,驱动表根本没得选。

