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