Python技术迷

MySQL多表联查实战大全:7种核心方法与优化技巧

我昨晚在办公室加班到快十一点,楼下保安都开始打哈欠了,我还在盯着 MySQL 的慢查询日志。说实话,多表联查真的是开发里最容易“坑自己”的地方,表一多,SQL 一复杂,稍微写不对就要命。今天就聊聊 MySQL 多表联查实战大全,我会把 7 种常见的写法都掰开揉碎讲一遍,还会顺便带上优化技巧,尽量口语化点,大家看着别犯困。

一、最基础的:INNER JOIN

这个大家应该用得最多吧,内连接就是把两个表里能匹配的数据拿出来。比如我有用户表 users 和订单表 orders,想查一下用户的订单情况:

SELECT u.id, u.name, o.order_no, o.amount
FROMusers u
INNERJOIN orders o ON u.id = o.user_id;

这里 INNER JOIN 的意思就是必须在两边都有匹配的记录才会出来。你要是某个用户没下单,那他在结果里就看不到。

二、LEFT JOIN:保留左边的

很多人写报表的时候,都遇到过“要把所有用户都列出来,不管他有没有下过单”。这个时候 LEFT JOIN 就派上用场了。

SELECT u.id, u.name, o.order_no, o.amount
FROMusers u
LEFTJOIN orders o ON u.id = o.user_id;

这样,哪怕 orders 里没有对应的数据,也会把用户列出来,只是订单相关的字段会是 NULL。这点在做统计的时候特别有用,比如要算“多少人从来没买过东西”。

三、RIGHT JOIN:保留右边的

这个和 LEFT JOIN 反过来,但老实说我在项目里几乎不用。多数人都习惯写左表是主表,这样思路更直观。如果真要用也行:

SELECT u.id, u.name, o.order_no
FROMusers u
RIGHTJOIN orders o ON u.id = o.user_id;

效果就是订单全保留,哪怕有些订单找不到对应用户。

四、FULL OUTER JOIN(MySQL 里没直接支持)

这个很多人会被问到,尤其是面试。MySQL 没有 FULL OUTER JOIN,但可以用 UNION 来模拟。比如我们想要把左右两边的数据都保留:

SELECT u.id, u.name, o.order_no
FROMusers u
LEFTJOIN orders o ON u.id = o.user_id
UNION
SELECT u.id, u.name, o.order_no
FROMusers u
RIGHTJOIN orders o ON u.id = o.user_id;

虽然写起来有点啰嗦,但效果差不多。

五、CROSS JOIN(笛卡尔积)

这个基本不用,除非是做某种组合查询。它会把两张表的记录两两组合,N×M 条数据。比如:

SELECT u.name, p.product_name
FROMusers u
CROSSJOIN products p;

用户表有 100 条,商品表有 50 条,那结果就是 5000 条。别乱写,不然服务器直接给你跪。

六、自连接(SELF JOIN)

有些场景挺常见,比如部门表 departments 里,每个部门都有一个 parent_id,要查树形结构,就得自连。

SELECT d1.id, d1.name, d2.name AS parent_name
FROM departments d1
LEFTJOIN departments d2 ON d1.parent_id = d2.id;

这样就能查出每个部门和它上级的名字。

七、多表链式 JOIN

最后一种就是“连环套娃”,三张表、四张表连起来。比如用户下了订单,订单里又有商品,那我们就要同时查三张表:

SELECT u.name, o.order_no, p.product_name, p.price
FROMusers u
INNERJOIN orders o ON u.id = o.user_id
INNERJOIN products p ON o.product_id = p.id;

这类 SQL 在实际业务里特别常见,比如商城系统,一查就是用户、订单、商品、优惠券一起拼。

那么问题来了:怎么优化?

我踩过的坑太多了,说几个关键点:

  1. 加索引:联查条件里的字段,必须有索引,比如 orders.user_id。不然一跑就全表扫描,慢得要死。
  2. 控制返回列:不要 SELECT *,只查需要的字段。尤其多表联查时,结果集非常大。
  3. 小表驱动大表:EXPLAIN 看执行计划,保证驱动表的数据量小,减少计算。
  4. 尽量避免子查询:尤其是 IN 里套子查询,性能堪忧,可以改成 JOIN。
  5. 善用覆盖索引:有时候加个联合索引能少回表几万次,性能直接翻倍。
  6. 拆分复杂查询:有些业务逻辑太复杂,别贪图一条 SQL 搞定,拆成几步临时表会更快。

Python 小插曲:用代码跑一下

有时候我们需要在 Python 里执行这些 SQL,举个例子,用 pymysql:

import pymysql

conn = pymysql.connect(host="localhost", user="root", password="123456", database="shop")
cursor = conn.cursor()

sql = """
SELECT u.name, o.order_no, p.product_name
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id
"""

cursor.execute(sql)

for row in cursor.fetchall():
    print(row)

cursor.close()
conn.close()

这样就能把多表联查结果直接拿到 Python 里处理,特别适合做报表或者数据分析。

我之前遇到过一个线上事故,就是一条 5 表联查的 SQL,被同事写成了 SELECT *,结果跑了十几秒还没出来,把 MySQL CPU 打满,线上差点挂掉。后来一看,问题就出在没索引 + 多余字段。真的是血的教训。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领