mysql优化器通过成本估算穷举left-deep连接顺序,而非按sql书写顺序执行;它基于rows、filtered、索引等计算预估代价,选择最低成本路径,explain显示的即最终物理顺序。

MySQL优化器基于成本估算穷举所有left-deep连接顺序
它不是按SQL书写顺序执行,也不是简单选“小表”或“左表”,而是对所有可能的表连接排列(受限于left-deep树结构)逐个计算预估成本,挑最低的那个。这个过程叫join order optimization,从MySQL 5.7起默认开启。
关键输入包括:rows(预估扫描行数)、filtered(条件过滤后剩余比例)、索引可用性、临时表开销、IO代价等。你看到的EXPLAIN输出中table列从上到下,就是它最终选定的物理执行顺序。
- 优化器会先做range analysis:对每个WHERE/ON中的等值或范围条件单独评估,比如
A.name = 'xxx'预估返回51行,B.type = 'y'预估返回1行,这些数字直接影响排序权重 - 它用采样方式估算InnoDB索引页数据分布,不依赖直方图(MariaDB已支持,MySQL 8.0+仍靠采样)
- LEFT JOIN会限制重排自由度——优化器通常不敢把右表提前,因为要保证左表全量保留;但若左表本身无有效过滤,它仍可能把右表物化后再反向匹配
为什么EXPLAIN显示的顺序和你写的不一样?
因为你写的只是逻辑依赖参考,不是执行指令。比如SELECT * FROM A JOIN B ON ... JOIN C ON ...,优化器发现C过滤后只剩2行,而B有50万行且没合适索引,就可能把C提到最前,再JOIN A,最后JOIN B——只要语义等价,它就敢改。
常见误解是“LEFT JOIN必须左表驱动”,其实驱动关系由成本决定;只是LEFT语义约束让优化器更保守,尤其当左表结果集大、右表又没索引时,它大概率老老实实按你写的顺序走,但这不是规则,是妥协。
-
EXPLAIN FORMAT=TREE(MySQL 8.0+)能直观看到嵌套结构和驱动层级 -
rows×filtered≈ 实际参与JOIN的行数,比单看rows更有参考价值 - 如果某张表
rows极大但filtered接近100%,说明条件没走索引,得查字段类型、隐式转换或函数包裹问题
ON条件写错位置会让优化器“误判”驱动表
把本该在ON里的右表过滤条件挪到WHERE,不仅语义退化为INNER JOIN,还会让优化器误以为右表必须全量加载后再过滤——它看不到“其实这部分数据早该被筛掉”,于是放弃把右表当驱动表的可能。
例如orders LEFT JOIN users ON orders.user_id = users.id WHERE users.status = 'active',优化器会认为users必须先全表扫描,再和orders拼接,最后筛status;而改成ON ... AND users.status = 'active',它就知道users可直接用(id, status)索引快速定位,甚至可能把它提为驱动表。
- 复合
ON条件如a.x = b.y AND b.z > 10,b.z > 10是在JOIN阶段生效的,等效于提前WHERE,能显著缩小被驱动表数据集 - LEFT JOIN中每个
ON只约束紧邻右侧的表,A LEFT JOIN B ON ... LEFT JOIN C ON B.id = C.b_id里,C无法感知A的字段,也不能用A的条件下推 - 多表LEFT JOIN时,若中间某张右表返回大量NULL(比如配置表无匹配),后续JOIN会放大空行,进一步拖慢整体速度
STRAIGHT_JOIN不是银弹,用错反而更慢
它强制禁用优化器重排,按SQL中表出现顺序执行,只对INNER JOIN有效,LEFT/RIGHT JOIN不支持。你以为的小表驱动,可能因数据分布变化(比如某天small_table突然涨到千万行)立刻崩盘。
真正该做的是让优化器“愿意”选你期望的顺序:建好ON字段索引、用强WHERE缩小驱动表结果集、定期ANALYZE TABLE更新统计信息。硬上STRAIGHT_JOIN前,必须用EXPLAIN和真实压测对比,否则上线后性能雪崩不是假设。
-
STRAIGHT_JOIN语法是SELECT * FROM t1 STRAIGHT_JOIN t2 ON ...,不能写成JOIN STRAIGHT_JOIN - 它绕过所有成本评估,一旦索引失效或数据倾斜,就会触发全表扫描级联
- 容器环境(如MySQL 9.6.0 +
container_aware)下,资源隔离可能导致采样偏差变大,STRAIGHT_JOIN风险更高
复杂点在于:优化器的“成本”模型依赖采样和静态统计,而真实查询受并发、buffer pool热度、锁竞争影响极大;EXPLAIN给的只是快照,不是预言。最容易被忽略的是filtered列——它常被当成次要指标,但恰恰是判断条件是否真正生效的关键。











