《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,恭喜你,我们有了更高端的算法。

  • 逻辑:把小表在内存里建成哈希表,大表扫描一次,秒级匹配。
  • 感受:就像给每个人发了个对讲机,喊一嗓子就知道谁在。
  • 注意:没有银弹。这虽然快,但也得吃内存。如果小表也大到内存装不下,则触发「磁盘临时表」模式,这时候性能依然会崩。

给业务开发的“三条保命建议”:

  1. “谁先追谁”很重要(小表驱动大表
    虽然 MySQL 优化器很聪明,通常会帮我们选好。但作为开发,我们要有意识地让结果集小的表去当驱动表。记住,是“结果集”,不是总行数。如果你用了 LEFT JOIN,左表就是老大,MySQL 哪怕知道它很大也会含着泪去跑。
  2. 别带“全家老小”去约会(拒绝 SELECT *
    JOIN 的时候,每一行被选中的列都会进 join_buffer。你多选一个无用的 TEXT 大字段,就像约会时带了全村人,join_buffer 一下子就挤爆了,性能直接从 5G 跌到 2G。
  3. 婚姻的基石(字符集的一致性
    这是我之前在技术文档里反复提到的“陷阱”。如果两张表的字符集一个叫 utf8,一个叫 utf8mb4,对不起,索引会失效!就像一个讲温州话,一个讲东北话,完全沟通不了,只能暴力全表扫描。

DBA 的最后叮嘱:

大家在写 SQL 的时候,记得多用 EXPLAIN。如果看到 rows 很大或者出现了 Using join buffer (Block Nested Loop),那可能就是系统在向你求救。

总结一句话:连接字段加索引,小表驱动没烦恼。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐