JOIN 连接:到底能不能写 JOIN?
很多开发同学下意识地认为 JOIN 会降低 SQL 性能,于是把多表查询拆成单表查询。但这样反而更慢——因为不了解 JOIN 的实现过程。
一、JOIN 的两种算法
MySQL 8.0 支持两种 JOIN 算法:
| 算法 | 适用场景 | 特点 |
|---|---|---|
| Nested Loop Join | OLTP(小数据量、有索引) | 用索引逐行匹配 |
| Hash Join | OLAP(大数据量、无索引) | 用哈希表批量匹配 |
1. Nested Loop Join
驱动表 R → 通过索引查询关联表 S示例:
sql
SELECT * FROM orders o
INNER JOIN lineitem l ON o.o_orderkey = l.l_orderkey
WHERE o.o_orderdate >= '1994-02-01';执行流程:
1. 用 idx_orderdate 过滤 orders(驱动表)
2. 对每条订单,用主键查 lineitem
3. 返回匹配结果驱动表选择原则:谁过滤后的数据量少,谁就是驱动表。
2. Hash Join
扫描小表 → 创建哈希表 → 扫描大表 → 哈希匹配适用于:没有索引、数据量大的场景。
二、OLTP 能不能写 JOIN?
完全可以! 但要满足两个条件:
- WHERE 条件能过滤到少量数据
- JOIN 的列上有索引
示例(用户查订单):
sql
SELECT o_custkey, o_orderdate, o_totalprice, p_name
FROM orders o, lineitem l, part p
WHERE o.o_orderkey = l.l_orderkey
AND l.l_partkey = p.p_partkey
AND o.o_custkey = ? -- 用户ID过滤
ORDER BY o.o_orderdate DESC
LIMIT 30;执行计划显示只扫描 30 条数据,无论表有多大,速度都很快。
三、JOIN 使用建议
| 场景 | 能否写 JOIN | 注意事项 |
|---|---|---|
| OLTP(电商、支付) | 可以 | 确保驱动表数据量少、有关联索引 |
| OLAP(报表、分析) | 可以 | 大数据量用 Hash Join |
| 无索引关联 | 慎用 | 先加索引或考虑拆分成多次查询 |
核心原则:相信优化器,它比你更专业。确保索引到位,放心写 JOIN!