为什么CROSS JOIN在SQL生产环境下如此危险?因为不带条件的CROSS JOIN会强制生成笛卡尔积。而在生产环境中,数据量会让这个乘积瞬间超出内存、磁盘和连接池的承载能力——不是“可能慢”,而是“必然崩”。

执行计划里 rows 预估超 10 万就该警觉
别靠经验猜,直接看EXPLAIN输出:如果type是ALL或index,且rows显示值远大于任一表的实际行数(比如左表5万行、右表8万行,rows却标4e9),那笛卡尔积就坐实了。出现Using join buffer或Using temporary,说明内存不够,开始落盘排序,性能会断崖式下跌。Extra里有Using where; Using filesort,但WHERE条件是1=1或为空,等于优化器已经放弃索引选择。这种情况下,必须警惕。
加 LIMIT 并不能真正止血
LIMIT在CROSS JOIN后面加,只是最后截断,不是提前剪枝。错误写法是:SELECT * FROM a CROSS JOIN b LIMIT 100——先算完全部组合(比如10亿行),再取前100行,照样OOM。正确做法是:必须配合ORDER BY字段有索引,且把排序+截断逻辑前置,例如:SELECT * FROM (SELECT * FROM a ORDER BY id LIMIT 100) a_sub CROSS JOIN b。注意:max_execution_time在MySQL中对CROSS JOIN不一定生效,尤其在子查询或MyISAM表里完全无效。
过滤条件必须写在 JOIN 前,而不是 WHERE 后
多数引擎(包括Hive、PostgreSQL、SQL Server)不会把WHERE条件下推到CROSS JOIN的任一侧。危险写法:SELECT * FROM orders CROSS JOIN product_catalog WHERE orders.order_date = '2024-01-01'——先爆1000万×5000行中间结果,再过滤。安全写法:用CTE或子查询先筛好左表:WITH filtered_orders AS (SELECT * FROM orders WHERE order_date = '2024-01-01') SELECT * FROM filtered_orders CROSS JOIN product_catalog。同样适用于右表:如果product_catalog实际只需用其中100款热门商品,就得先SELECT * FROM product_catalog WHERE is_hot = 1再JOIN。这点必须明确,不能依赖WHERE后置过滤。
小维度表才配用 CROSS JOIN,业务大表一律禁止
真正合法的CROSS JOIN场景极少,只限于可控的小结果集。可接受:dim_month(12行)× dim_region(34行)→最多408行。可接受:用UNION ALL构造的枚举表,如血型(4行)、状态(3行)→组合最多12行。禁止:user_logs(日增百万)、events(滚动千亿)、orders(千万级)参与任何CROSS JOIN。特别容易被忽略的是:开发环境数据量小,EXPLAIN显示rows=2000,上线后数据翻十倍,rows变成2000万,优化器依然安静地执行,直到服务器拒绝新连接。话又说回来,生产环境下的CROSS JOIN,必须慎之又慎。
