4.2 多表连接 JOIN


4.2 多表连接 JOIN

本节摘要:JOIN 把多张表按关联条件连成一张结果表。本节讲 INNER/LEFT/RIGHT/FULL 四种 JOIN 的区别和用法,以及 JOIN 的写法和性能注意。

你能学到什么

阅读完本节,你应当能够:

  1. 区分四种 JOIN 的结果差异
  2. 写出标准 JOIN 语法
  3. 用表别名简化 JOIN
  4. 理解 JOIN 的性能注意

概念脉络

一、为什么需要 JOIN

数据分散在多张表里(第 2 章讲的关系模型),查"每个客户的订单金额"要把 Customers 和 Orders 连起来,这就是 JOIN。JOIN 按关联条件(通常是主外键)把两表的行配对。

SELECT Customers.FirstName, Orders.Amount FROM Customers JOIN Orders ON Customers.CustomerID = Orders.CustomerID;

二、四种 JOIN

图 4-2 四种 JOIN 对比图

图 4-2 四种 JOIN 对比图

四种 JOIN 的区别在于"保留哪边":

  • INNER JOIN:只保留两边都匹配的行(交集)。
  • LEFT JOIN:左表全保留,右表没匹配的填 NULL。
  • RIGHT JOIN:右表全保留,左表没匹配的填 NULL。
  • FULL JOIN:两边全保留,没匹配的填 NULL。
-- 所有客户及其订单(没订单的客户也显示,金额为 NULL) SELECT Customers.FirstName, Orders.Amount FROM Customers LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;

三、表别名

JOIN 涉及多表,列名可能重名(如两表都有 CustomerID),用表别名前缀区分,并给表起短别名简化:

SELECT c.FirstName, o.Amount FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID;

Customers c 给表起别名 c,后面用 c.CustomerID 引用。多表 JOIN 必用别名,否则写起来很长。

四、多表 JOIN

可以连续 JOIN 多张表:

SELECT c.FirstName, o.Amount, p.ProductName FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID JOIN OrderItems oi ON o.OrderID = oi.OrderID JOIN Products p ON oi.ProductID = p.ProductID;

五、JOIN 的性能注意

  • 关联条件要有索引:JOIN 的关联列(通常是外键)建索引,否则全表扫描很慢。
  • 先过滤再 JOIN:用 WHERE 先缩小各表数据,再 JOIN,减少配对量。
  • 避免笛卡尔积:忘写 ON 条件会得到两表所有组合(笛卡尔积),行数爆炸。

⚠️ 常见坑:JOIN 忘写 ON 条件,得到笛卡尔积——1000 行 × 1000 行 = 100 万行,查询爆炸。JOIN 必须有 ON 条件。

💡 关键直觉:JOIN 按 ON 条件配对两表行,INNER 取交集、LEFT 左全、RIGHT 右全、FULL 全集。关联列建索引,多表 JOIN 用别名简化。

本章回顾

  • JOIN 按关联条件连表,通常是主外键。
  • 四种 JOIN:INNER(交集)、LEFT(左全)、RIGHT(右全)、FULL(全集),没匹配的填 NULL。
  • 表别名:多表 JOIN 必用,表 别名 起短名,用 别名.列 引用。
  • 多表 JOIN:连续 JOIN,每步一个 ON 条件。
  • 性能:关联列建索引、先过滤再 JOIN、别忘 ON 条件(避免笛卡尔积)。

下一节讲子查询——把查询嵌进查询。

常见疑问

Q1:JOIN 忘记写 ON 条件会发生什么?

变成笛卡尔积:左表每一行和右表每一行都组合。两表各 1000 行就出 100 万行,既慢又没意义。这是新手最容易犯的错,务必写完 JOIN 检查 ON 是否齐全。

Q2:INNER JOIN 和 LEFT JOIN 结果行数怎么判断?

INNER 只返回两边匹配上的行;LEFT 返回左表所有行,右表没匹配上的用 NULL 补齐。判断行数时记住:LEFT JOIN 结果行数大于等于左表行数(右表有重复匹配时更多)。写 JOIN 前先想清楚"要保留哪边的所有行"。

Q3:三张表以上怎么 JOIN?

逐个连:A JOIN B ON ... JOIN C ON ...。注意连接顺序和条件归属。三表 JOIN 时,建议每步都写清楚 ON,并只关联必要的表,避免无谓的行数膨胀。

Q4:JOIN 时怎么用 WHERE 过滤?

可以在 JOIN 之后加 WHERE 过滤结果。但要注意:LEFT JOIN 后对右表列加 WHERE 条件,会把"没匹配上的 NULL 行"过滤掉,效果变成 INNER JOIN。如果想保留左表全部,过滤条件要放在 ON 里或先对右表做子查询过滤。这是 JOIN 进阶最重要的坑。

Q5:关联列必须有索引吗?

是。JOIN 本质是"用左表每行去右表找匹配",右表关联列有索引才能高效查找,否则全表扫描。外键列一般自动建索引或建议建索引。慢 JOIN 的首要排查项就是关联列索引。

Q6:FULL JOIN 为什么用得少?

因为两边都不匹配的行都保留,语义"全量",实际业务中"既要左表全部又要右表全部"的场景少。且 MySQL 不支持 FULL JOIN(需用 UNION 模拟),所以日常以 INNER、LEFT 为主。

动手做一做

连接是理解和练习并重的主题,建议用最笨也最有效的方式:手动画表。

准备两个小表,比如客户表和订单表,各插入三五条数据,其中让部分客户没有订单、部分订单没有对应客户。

第一步,把两表内容画在纸上,左边一列客户,右边一列订单。

第二步,手动模拟内连接:把两边都能匹配上的行配成对,数一数结果有几行,记住内连接"只保留两边都有"。

第三步,手动模拟左连接:左边所有行都保留,右边配不上的补上"空"标记,再数一次行数,记住左连接"左边全保留"。

第四步,把同样的模拟做到右连接和全连接上,对比四种结果的行数和"谁被保留"。

第五步,再把模拟结果和数据库实际查询结果对比,确认你的理解无误。

这五步做完,四种连接的差别就不是背出来的,而是你自己推演出来的。连接是面试必考、工作常用的主题,这份亲手推演的体验,比任何口诀都可靠。

一句话记忆

连接的本质是按条件给两边的行配对。内连接只留配上的,左连接左全留,右连接右全留,全连接全留。忘写条件会变成笛卡尔积,关联列要有索引才高效。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U