inner join 默认取交集,缺on条件会触发笛卡尔积;left join中右表条件须放on而非where,否则变inner join;自连接需别名,多对多须中间表;union与子查询不可替代join。

INNER JOIN 是默认交集,不加条件会炸出笛卡尔积
MySQL 的 INNER JOIN 只返回两张表中连接字段值完全匹配的行,本质是取“交集”。但很多人第一次写就翻车——忘了写 ON 条件,结果查出几百万行垃圾数据。
- 没写
ON或WHERE连接条件 → 触发隐式CROSS JOIN,结果行数 = 左表行数 × 右表行数(笛卡尔积) -
ON和WHERE都能筛数据,但语义不同:ON控制“怎么连”,WHERE控制“连完再筛”;外连接里放错位置会导致 NULL 行被意外过滤 - 连接字段类型要一致:比如
dept_id INT去连id VARCHAR,MySQL 可能隐式转换但性能暴跌,还容易漏匹配
示例:正确写法是 SELECT e.name, d.name FROM emp e INNER JOIN dept d ON e.dept_id = d.id;错写成 ...JOIN dept d(缺 ON)就危险了。
LEFT JOIN 保左表全量,但 WHERE 后跟条件会悄悄变 INNER
LEFT JOIN 的本意是“左表全出来,右表有就拼,没有就填 NULL”。可一旦在 WHERE 里对右表字段加判断(比如 WHERE d.name = '研发部'),那些原本为 NULL 的行就被干掉了——效果等同于 INNER JOIN。
- 想保留左表所有员工,同时只显示部门名为“研发部”的关联信息?得把条件挪到
ON里:LEFT JOIN dept d ON e.dept_id = d.id AND d.name = '研发部' - 右表字段参与
WHERE筛选前,先确认是否允许为 NULL;否则逻辑会偏离预期 - 多表 LEFT JOIN 时,后一个 JOIN 的
ON只能引用前序已引入的表,不能跨跳(比如从第 1 表直接引用第 3 表字段)
自连接和多对多中间表,是层级与关系建模的硬需求
员工查领导、评论查父评论、菜单查子菜单——这类“自己连自己”的场景必须用自连接;而学生选多门课、课程被多人选,这种多对多关系不靠中间表根本没法干净表达。
- 自连接必须用别名区分逻辑角色:
emp AS e(员工)和emp AS m(经理),否则字段冲突、语义混乱 - 多对多中间表不是可选项:它得有至少两个外键(如
student_id,course_id),且通常设联合主键或唯一索引,否则数据会重复或无法约束 - 查“选了数学又选了英语的学生”,不能靠两次
LEFT JOIN硬拼,要用IN+ 子查询 或GROUP BY+HAVING COUNT(DISTINCT ...)
示例中间表结构:student_course(studentid INT, courseid INT, FOREIGN KEY(studentid) REFERENCES student(id))。
UNION 和子查询不是 JOIN 替代品,混用容易语义断裂
UNION 是纵向合并结果集,JOIN 是横向拼字段,目标完全不同。子查询(尤其 IN 或 EXISTS)看似能替代连接,但性能和可读性常不如显式 JOIN。
-
UNION要求列数、类型、顺序严格一致;UNION ALL比UNION快,因不 dedup,但业务上是否允许重复得你自己判 -
WHERE dept_id IN (SELECT id FROM dept WHERE name = '销售部')看似简洁,但 MySQL 8.0 前可能转成 N+1 查询;改用JOIN通常更稳 -
EXISTS适合“是否存在”类判断,IN对空值敏感(NULL在子查询结果里会让整行失效),这点极易被忽略
真正该用 JOIN 的时候,别为了“看起来短”硬套子查询——执行计划和维护成本很快会让你回来。
连接字段要不要加索引、NULL 值怎么参与匹配、LEFT JOIN 后再 GROUP BY 是否丢失 NULL 行……这些细节不会报错,但会让结果静默失真。动手前先想清楚:你到底要的是“匹配上的数据”,还是“左边所有数据及其匹配状态”。











