inner join 仅保留 on 条件为 true 的行组合,null 参与判断结果为 unknown 而被丢弃;on 应用显式等值、类型一致、字符集匹配的条件,且字段需有索引;函数或模糊匹配会导致索引失效。

INNER JOIN 是怎么决定哪几行能连上的
内连接只保留左右两张表中 ON 条件为 TRUE 的行组合,不满足的整行丢弃。它不是“找相似”,而是“严格配对”——哪怕某字段值是 NULL,只要参与 ON 判断,结果就是 UNKNOWN,这行就不会出现在结果里。
常见错误现象:LEFT JOIN 能查出数据,换成 INNER JOIN 就没结果了,大概率是关联字段存在 NULL 或类型隐式转换失败。
-
ON后面的条件必须写成table1.col = table2.col这种显式等值判断,不能写成table1.col LIKE table2.col(除非你真需要模糊匹配,但那就不是标准 inner join 语义了) - 字段类型要一致:比如
INT和VARCHAR比较,MySQL 可能转成数字再比,'123abc'会变成123,导致意外匹配或不匹配 - 字符集和排序规则(collation)不同也会让相等判断失败,尤其跨库或历史表迁移后容易踩坑
ON 和 WHERE 都能过滤,到底该放哪儿
放错位置会导致逻辑完全不同。ON 是连接时的“配对规则”,WHERE 是连接完成后的“结果筛选”。对 INNER JOIN 来说,表面看效果常一样,但执行顺序和可读性差很远。
使用场景:比如查订单和用户,想只看「北京用户的已支付订单」——user.city = '北京' 应该放在 ON 子句里(作为连接前提),而 order.status = 'paid' 放 WHERE 更自然。
- 把本该在
ON的关联条件挪到WHERE,会让 SQL 可读性下降,后续改成LEFT JOIN时极易出错 - 如果
WHERE中包含左表字段的非空限制(如WHERE t1.id IS NOT NULL),对INNER JOIN没影响;但若误用于LEFT JOIN,就会把本该保留的左表空匹配行也干掉 - MySQL 优化器有时会重排条件,但别依赖它——写清楚意图比赌优化器更可靠
多表 INNER JOIN 的顺序影响性能吗
会影响,特别是当表大小差异大、索引分布不均时。MySQL 默认按 FROM 后顺序驱动,先查的表叫“驱动表”,它的结果集大小直接决定后续连接的循环次数。
性能影响:假设 orders 有 100 万行,users 有 10 万行,products 有 5000 行。写成 FROM orders JOIN users ON ... JOIN products ON ...,很可能让 MySQL 先扫百万级订单,再对每条去查用户和商品。
- 优先把最小、过滤性最强的表放最左(即驱动表),比如加了
WHERE order_date > '2024-01-01'后orders实际返回才 1 万行,那它就适合当驱动表 - 确保
ON字段上有索引,且是复合索引的最左前缀——例如JOIN user_orders uo ON uo.user_id = u.id,那user_orders(user_id)必须有索引 - 用
EXPLAIN看rows和type,如果出现ALL或预估行数远超实际,基本就是驱动顺序或索引没用上
为什么 ON 条件里用了函数就变慢甚至失效索引
因为 MySQL 无法直接拿函数结果去走索引 B+ 树。比如 ON DATE(o.create_time) = DATE(u.register_time),数据库得先把两列全算一遍 DATE(),再逐行比,索引完全作废。
错误现象:原本毫秒级的关联,加个 UPPER() 或 SUBSTRING() 就变几十秒,EXPLAIN 显示 type: ALL。
- 尽量把函数移到等号右边,或者提前计算好字段存起来——例如建一个生成列
create_date DATE AS (DATE(create_time)) STORED,再给它加索引 - 字符串比较慎用
LIKE '%xxx'做ON条件,B+ 树没法从右往左查,必然全表扫 - 时间范围关联别用函数截断,改用区间:
ON o.create_time >= u.register_time AND o.create_time
真正难的不是写对语法,是想清楚“我到底要哪几行配对”——NULL 怎么处理、字段类型是否真一致、驱动顺序有没有被业务条件悄悄改变,这些地方不动手跑一遍 EXPLAIN,光看 SQL 很难发现。










