MySQL JOIN 指南:如何避免在数据库里谈一场倾家荡产的恋爱
·
文章目录
《MySQL JOIN 指南:如何避免在数据库里谈一场倾家荡产的恋爱》
在 MySQL 的世界里,JOIN 就像是一场相亲会。如果相得好,那就是“金风玉露一相逢,便胜却人间无数”;如果相不好,那就是“伤心秦汉,生灵涂炭”。
1. 门当户对:Index Nested-Loop Join (INLJ)
这是最理想的恋爱状态。
- 逻辑:驱动表(男方)拿着条件,去被驱动表(女方)那里找,被驱动表的连接字段有索引。
- 感受:就像男方拿着“身份证号”去民政局查,一查一个准。
- DBA 建议:连接字段一定要加索引! 如果没有索引,MySQL 就得在被驱动表里玩“大海捞针”,这不仅是浪费时间,这是在浪费青春。
2. 凑合过吧:Block Nested-Loop Join (BNL)
当连接字段没索引时,MySQL 就会祭出这个大招。
- 逻辑:把驱动表的一堆数据塞进
join_buffer(暂存区),然后全表扫描被驱动表,在内存里肉搏匹配。 - 感受:这不叫相亲,这叫“全城大搜捕”。极其消耗 CPU/IO,若被驱动表是大冷表,还会把 Buffer Pool 里的热数据全洗掉,影响内存命中率。
- DBA 吐槽:在 MySQL 8.0 之前,这是性能杀手。如果你发现 SQL 执行计划里出现了
Using join buffer (Block Nested Loop),请立刻、马上、现在给你的被驱动表加个索引!
3. 秘密武器:Hash Join (MySQL 8.0+)
如果你们已经升级到了 MySQL 8.0.18,恭喜你,我们有了更高端的算法。
- 逻辑:把小表在内存里建成哈希表,大表扫描一次,秒级匹配。
- 感受:就像给每个人发了个对讲机,喊一嗓子就知道谁在。
- 注意:没有银弹。这虽然快,但也得吃内存。如果小表也大到内存装不下,则触发「磁盘临时表」模式,这时候性能依然会崩。
给业务开发的“三条保命建议”:
- “谁先追谁”很重要(小表驱动大表):
虽然 MySQL 优化器很聪明,通常会帮我们选好。但作为开发,我们要有意识地让结果集小的表去当驱动表。记住,是“结果集”,不是总行数。如果你用了LEFT JOIN,左表就是老大,MySQL 哪怕知道它很大也会含着泪去跑。 - 别带“全家老小”去约会(拒绝 SELECT *):
JOIN 的时候,每一行被选中的列都会进join_buffer。你多选一个无用的TEXT大字段,就像约会时带了全村人,join_buffer一下子就挤爆了,性能直接从 5G 跌到 2G。 - 婚姻的基石(字符集的一致性):
这是我之前在技术文档里反复提到的“陷阱”。如果两张表的字符集一个叫utf8,一个叫utf8mb4,对不起,索引会失效!就像一个讲温州话,一个讲东北话,完全沟通不了,只能暴力全表扫描。
DBA 的最后叮嘱:
大家在写 SQL 的时候,记得多用 EXPLAIN。如果看到 rows 很大或者出现了 Using join buffer (Block Nested Loop),那可能就是系统在向你求救。
总结一句话:连接字段加索引,小表驱动没烦恼。
更多推荐

所有评论(0)