该用CROSS JOIN而非逗号语法时,是为了明确表达“故意生成笛卡尔积”的意图,避免被误读为漏写ON条件;它不支持ON/USING子句,适用于需全组合的场景(如日期×门店占位),但须警惕因输入表过大导致的性能爆炸。

什么时候该用 CROSS JOIN 而不是逗号语法
直接写 SELECT * FROM a, b 确实也能得到笛卡尔积,但 CROSS JOIN 更明确表达“无意连接条件、纯组合”的意图。尤其在复杂查询中混用 JOIN 类型时,逗号语法容易被误读为遗漏 ON 条件——而 CROSS JOIN 一出现,你就知道这里是故意要爆炸式组合。
实际场景比如:生成所有日期 × 所有门店的占位记录;枚举所有产品 × 所有销售状态用于补全报表维度。
注意:CROSS JOIN 不接受 ON 或 USING 子句,写了会报错,例如 CROSS JOIN b ON a.id = b.id 是非法语法。
CROSS JOIN 的性能风险在哪
笛卡尔积结果行数 = 左表行数 × 右表行数。1万行 × 1万行 = 1亿行,内存和网络都可能撑不住。别在没加 WHERE 过滤或没限流的情况下直接 SELECT *。
常见踩坑点:
- 忘记对大表做预过滤,比如先用子查询或 CTE 把右表缩到几十行再
CROSS JOIN - 在视图或嵌套查询里隐式触发
CROSS JOIN,导致上游调用方完全没意识到数据量爆炸 - MySQL 8.0+ 对
CROSS JOIN不走索引优化,它不尝试推导任何谓词下推,纯暴力组合
验证方法:执行前加 EXPLAIN,看 rows 列是否远超任一输入表的行数。
和 INNER JOIN 漏写 ON 的区别
这是最常混淆的点:漏写 ON 的 INNER JOIN 在标准 SQL 中是语法错误(PostgreSQL/SQL Server 会直接拒掉),但 MySQL 会悄悄把它当作 CROSS JOIN 处理——行为不一致,极易引发线上问题。
所以必须明确:
- 要笛卡尔积 → 显式写
CROSS JOIN - 要关联查询 → 必须写
INNER JOIN ... ON ...,绝不依赖 MySQL 的宽松解析 - 检查 SQL 模式:MySQL 开启
STRICT_TRANS_TABLES后,漏ON会报错,建议上线前统一配置
示例对比:
SELECT * FROM users CROSS JOIN roles; -- ✅ 清晰、跨数据库兼容
SELECT * FROM users INNER JOIN roles; -- ❌ MySQL 允许但危险,其他数据库报错
替代方案:用 GENERATE_SERIES 或递归 CTE 控制组合规模
如果只是想生成固定数量的组合(比如 1~100 的所有数字对),硬扫两张物理表既慢又浪费。PostgreSQL 有 GENERATE_SERIES,SQL Server 用 VALUES 构造小集合,SQLite 用 WITH RECURSIVE。
例如 PostgreSQL 中生成 1~3 和 1~4 的所有组合:
SELECT a, b FROM GENERATE_SERIES(1,3) AS a CROSS JOIN GENERATE_SERIES(1,4) AS b;
这种写法避免了建临时表,也杜绝了意外扫描大表的风险。关键是:笛卡尔积本身无害,失控的输入才致命。
真正难的不是写出 CROSS JOIN,而是判断哪边该提前聚合、哪边该用虚拟序列、哪次组合其实根本不需要落地成行——这些得看业务语义,不是语法能解决的。


















