LATERAL不是语法糖,而是执行模型的改变,要求MySQL 8.0.14+,必须显式书写且仅支持FROM或JOIN后;子查询需带别名、用等值条件关联并配合联合索引,否则退化为慢查询。

LATERAL 不是语法糖,它让子查询真正变成“每行调用一次”的函数式执行——但必须 MySQL 8.0.14+,且写法错一个字符就退化成慢查询。
必须显式写 LATERAL,且只能出现在 FROM 或 JOIN 后
MySQL 不接受隐式横向语义。哪怕子查询里写了 WHERE t.order_id = o.id,没加 LATERAL 关键字,就会当成普通派生表或相关子查询处理。
-
LATERAL必须紧贴子查询前,不能写成JOIN (LATERAL SELECT ...),括号位置错会直接报错syntax error at or near "LATERAL" - 只支持
INNER JOIN LATERAL和LEFT JOIN LATERAL;CROSS JOIN LATERAL虽语法合法,但语义等价于INNER JOIN LATERAL(子查询返回 0 行时主表行被丢弃) - 子查询必须带别名,哪怕只用一次,如
AS latest—— 缺少别名会触发解析失败
LATERAL 子查询里能用外层字段,但仅限等值条件
这是性能分水岭。优化器能否把关联下推、走索引,全看这一条。
- 允许:
WHERE l.order_id = o.id、AND l.status = 'shipped'—— 等值条件可下推,配合(order_id, update_time)联合索引,子查询能快速定位并LIMIT 1 - 禁止:
WHERE l.order_id < o.id、l.update_time BETWEEN o.created_at AND NOW()—— 非等值导致无法物化,退化为DEPENDENT SUBQUERY,EXPLAIN 显示select_type = DEPENDENT SUBQUERY,N×M 扫描 - 注意:子查询不能引用嵌套 CTE 中“上两层”的别名,比如 CTE A → CTE B → 主查询,B 里不能用 A 的列,否则报
Unknown column
LEFT JOIN LATERAL 的 ON true 是惯用写法,不是可有可无
因为关联逻辑已全部收口到子查询的 WHERE 中,ON 子句不需要再写条件。但若漏掉,MySQL 会要求显式连接条件,报错 ERROR 1064。
- 正确:
LEFT JOIN LATERAL (SELECT ... WHERE l.order_id = o.id ...) AS l ON true - 错误:
LEFT JOIN LATERAL (...) AS l(缺ON)或ON l.order_id = o.id(重复写关联,可能引发歧义或警告) -
LEFT JOIN LATERAL保证主表行不丢失;若用INNER JOIN LATERAL,子查询返回空时该主表行直接消失——和INNER JOIN语义一致
索引没建对,LATERAL 反而更慢
没有联合索引时,LATERAL 会为每一行主表数据,对子表做一次全表扫描。10 万订单 × 平均 5 条物流记录 = 50 万次扫描。
- 必须建覆盖索引:
ALTER TABLE logistics ADD INDEX idx_order_update (order_id, update_time)(MySQL 不支持DESC索引方向,但ORDER BY update_time DESC LIMIT 1仍可高效走索引) - 验证是否生效:用
EXPLAIN查看子查询部分,应出现type = ref或type = range,且key列显示用了你建的索引 - 避免踩坑:如果
update_time有大量重复值,LIMIT 1可能返回任意一条——需加二级排序,如ORDER BY update_time DESC, id DESC,并确保id在索引中或主键有序
真正难的从来不是写出 LATERAL 这三个字母,而是确认子查询是否真的按行执行、是否真的走了索引、以及当业务加了新条件(比如时间范围过滤)时,它会不会瞬间崩回相关子查询模式。


















