标准sql不推荐逗号分隔表名连接,因其本质是先笛卡尔积再过滤,导致性能差、易出错、难优化;显式join能明确连接意图、支持谓词下推、保障left join语义、暴露类型索引问题。

标准SQL早已明确不推荐用逗号分隔表名做连接,这不是风格偏好,而是语义模糊、易出错、难优化的硬伤。
逗号语法本质是 CROSS JOIN + WHERE 过滤
写 FROM a, b WHERE a.id = b.a_id 看似简洁,实际执行逻辑是先算笛卡尔积,再过滤。哪怕只有 100 行 × 100 行,也先生成 10000 行中间结果——而 INNER JOIN 允许优化器提前应用连接条件,跳过大量无效组合。
- 漏写一个
AND条件?直接触发全量笛卡尔积,rows在EXPLAIN里暴增十倍百倍 - 多表时条件分散在
WHERE里,人眼难判断哪条属于哪对表的关联逻辑 - 优化器无法对逗号语法做谓词下推(predicate pushdown),过滤时机被迫延后,中间结果体积更大
JOIN 显式声明连接意图,ON/WHERE 职责分离
ON 只管“怎么连”,WHERE 只管“连完留哪些”。这种分离在 LEFT JOIN 场景下尤其关键:
- 把本该写在
ON的o.status = 'paid'错挪到WHERE,就让LEFT JOIN退化成INNER JOIN,空值行全被筛掉 - 逗号语法没有
ON子句,所有条件都挤在WHERE,根本无法表达“左表保留、右表可空”的语义 - 现代 SQL linter(如
sqlfluff)能自动检测from_without_join类问题,但对逗号语法束手无策
类型与索引失效风险更隐蔽
逗号语法下,字段类型不一致的隐患更难察觉。比如 a.user_id 是 VARCHAR(32),b.user_id 是 INT,MySQL 会把整数转字符串比对,导致 b.user_id 索引完全失效——EXPLAIN 里 key 为 NULL,Extra 出现 Using where; Using join buffer。
- 显式
JOIN强制你审视每一对ON条件的字段定义,用SHOW CREATE TABLE核对类型、字符集、排序规则更自然 - USING 语法(如
JOIN b USING (id))虽能简化等值连接,但只适用于字段名和类型完全一致的场景,老版本兼容性差,不建议滥用
真正麻烦的不是语法转换本身,而是旧代码里混在 WHERE 中的连接条件没被拆出来——这种隐藏逻辑一旦漏改,查询语义就静默变更了。










