JOIN 语法写错会导致结果为空或笛卡尔积
MySQL 多表联合查询最常见问题不是“不会写”,而是
ON条件漏写、写错字段,或者误用
WHERE替代
ON。比如左连接时把关联条件放到
WHERE里,会把本该保留的左表空匹配行过滤掉,实际变成内连接效果。
实操建议:
所有JOIN后必须跟
ON,哪怕只是临时测试也别省略
LEFT JOIN的过滤条件:关联字段放
ON,左表自身条件放
WHERE,右表非空限制(如
t2.status = 'active')要放
ON,否则会失效 用
EXPLAIN看执行计划,重点检查
type是否为
ALL(全表扫描),以及
key是否用了索引
多对一/一对多场景下 GROUP BY 容易漏加字段
比如查「每个用户最新一条订单」,用
JOIN + MAX(order_time)再关联原表时,若没在
GROUP BY中包含用户所有需要展示的字段(如
user_name,
Expression #3 of SELECT list is not in GROUP BY clause。
实操建议:
开启sql_mode=ONLY_FULL_GROUP_BY(默认已开),强迫你写规范 不要依赖 MySQL 的“隐式分组”,宁可用子查询或窗口函数(MySQL 8.0+ 支持
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_time DESC)) 确认
GROUP BY字段和
SELECT中非聚合字段完全一致,包括别名不能混用
UNION 和 UNION ALL 性能差异比想象中大
当需要合并多个查询结果(如「今日订单 + 昨日订单」),很多人默认写
UNION,但它会自动去重 + 排序,即使你根本不需要。如果两个结果集天然无交集(比如按日期分割),用
UNION ALL能省掉排序和去重开销,实测快 2–5 倍。
实操建议:
只要确定结果不重复,一律优先用UNION ALL
UNION要求各子查询列数、类型兼容,遇到
INT和
VARCHAR混用会隐式转换,可能触发全表扫描 合并前先检查字段顺序是否一致,
SELECT a,b FROM t1 UNION SELECT b,a FROM t2是错的,字段位置必须对齐
关联字段类型不一致导致索引失效
这是线上最隐蔽的性能杀手:比如用户表
user_id是
BIGINT,订单表外键却是
VARCHAR(20),即使值看起来一样,MySQL 也无法走索引,
JOIN变成全表扫描。
实操建议:
用SHOW CREATE TABLE对比两边字段定义,特别注意
CHAR/
VARCHAR长度、有无
UNSIGNED、字符集是否一致(如
utf8mb4vs
utf8) 修改前先用
ALTER TABLE ... MODIFY COLUMN统一类型,避免用函数包装字段(如
CAST(t2.user_id AS SIGNED))来“绕过” 上线前在测试库用
EXPLAIN FORMAT=JSON查看
used_columns和
key_length,确认是否命中索引 关联逻辑越复杂,字段类型和 NULL 处理就越容易出岔子。别信“看着一样就行”,得让
DESCRIBE和
EXPLAIN说真话。
