当数据分散在多张表里时,单表查询往往不够用了。
这时你会开始接触:
JOIN这一篇的重点不是把 SQL 高级语法全部讲完,而是建立几个最常用的查询直觉。
关系型数据库的一大特点,就是数据通常不会全塞进一张大表。
例如:
usersorderscommentsarticles这样设计更清晰,也更容易维护。
但查询时,你又经常需要把相关信息拼起来看,这就是 JOIN 的用武之地。
先假设有两张表:
CREATE TABLE users (id integer PRIMARY KEY,name text NOT NULL);CREATE TABLE orders (id integer PRIMARY KEY,user_id integer,total_amount numeric(10, 2));
如果你想知道“每笔订单是谁下的”,就需要把 orders.user_id 和 users.id 对应起来。
INNER JOIN 只返回两边能匹配上的记录。
SELECT orders.id, users.name, orders.total_amountFROM ordersINNER JOIN users ON orders.user_id = users.id;
这条语句的意思是:
ordersusers如果某条订单的 user_id 对不上任何用户,这条订单不会出现在结果中。
LEFT JOIN 会保留左边表的所有记录,即使右边没有匹配项。
SELECT users.id, users.name, orders.total_amountFROM usersLEFT JOIN orders ON users.id = orders.user_id;
它的直觉是:
NULL这很适合查:
RIGHT JOIN 和 LEFT JOIN 是对称的:它会保留右边表的所有记录。
SELECT users.name, orders.idFROM usersRIGHT JOIN orders ON users.id = orders.user_id;
不过在实际写查询时,很多人更习惯用 LEFT JOIN,因为从左到右更容易读。只要调整表顺序,很多场景都能用 LEFT JOIN 表达。
子查询是“在一个查询里再嵌一个查询”。
例如:
SELECT nameFROM usersWHERE id IN (SELECT user_id FROM orders WHERE total_amount > 100);
它先查出“订单金额大于 100 的用户 ID”,再去 users 表里找对应用户。
用 JOIN 改写时可能是:
SELECT DISTINCT users.nameFROM usersINNER JOIN orders ON users.id = orders.user_idWHERE orders.total_amount > 100;
两者并不是谁绝对更高级,而是表达方式不同。
可以先这样理解:
入门阶段最重要的是:先把含义写对,再谈怎么优化。
复杂查询里,聚合非常常见。你不只是要“查出记录”,还经常要“统计结果”。
COUNT统计数量:
SELECT COUNT(*) FROM orders;
SUM求和:
SELECT SUM(total_amount) FROM orders;
AVG平均值:
SELECT AVG(total_amount) FROM orders;
MAX 和 MIN最大值与最小值:
SELECT MAX(total_amount), MIN(total_amount)FROM orders;
如果你想按用户统计订单数:
SELECT user_id, COUNT(*)FROM ordersGROUP BY user_id;
如果你还想把用户名一起带出来:
SELECT users.name, COUNT(orders.id)FROM usersLEFT JOIN orders ON users.id = orders.user_idGROUP BY users.id, users.name;
它表达的是:每个用户对应多少笔订单。
优化不是一上来就研究执行器内部细节,而是先建立一套朴素判断。
先确保结果正确,再谈性能。
如果逻辑都错了,优化没有意义。
例如:
WHERE例如在正式查询里,比起:
SELECT *
通常更推荐:
SELECT id, name
返回列越少,结果集通常也更轻。
例如:
orders.user_idusers.idorders.created_at这些字段是否有合适索引,往往会明显影响 JOIN 和筛选性能。
当你怀疑查询慢时,可以使用:
EXPLAIN SELECT * FROM orders WHERE user_id = 1001;
它会告诉你数据库打算怎么执行这条查询。
入门阶段不用一开始把执行计划的所有节点都读透,但至少要知道:优化不是靠猜,最终要回到执行方式。
假设你想查“每位用户的订单数量和总金额”:
SELECTusers.id,users.name,COUNT(orders.id) AS order_count,COALESCE(SUM(orders.total_amount), 0) AS total_amountFROM usersLEFT JOIN orders ON users.id = orders.user_idGROUP BY users.id, users.nameORDER BY total_amount DESC;
这个例子里同时用到了:
LEFT JOINCOUNTSUMCOALESCEGROUP BYORDER BY它已经很接近日常业务中的常见统计查询了。
理解 JOIN 时,最重要的不是背定义,而是记住:
INNER JOIN:只保留匹配上的LEFT JOIN:左边全保留RIGHT JOIN:右边全保留不需要。
真正更有价值的是:
先对,再快。这是非常重要的顺序。
你现在最值得先掌握的是:
INNER JOIN、LEFT JOIN、RIGHT JOIN 的区别COUNT、SUM、AVG、MAX、MIN 是最常见聚合函数下一篇会进入事务和并发控制:为什么两个用户同时改数据时,数据库仍然需要尽量保持一致和可靠。