MySQL Join关联查询的几种实现方式优化小结

 更新时间:2026年04月07日 10:15:09   作者:·云扬·  
在MySQL日常开发中,JOIN关联查询是高频操作,但相同的业务需求,不同的关联方式可能导致数倍的性能差异,下面就来详细的介绍一下MySQL Join关联查询的几种实现方式,感兴趣的可以了解一下

在MySQL日常开发中,JOIN关联查询是高频操作,但相同的业务需求,不同的关联方式可能导致数倍的性能差异。其核心症结在于Join算法的选择执行计划的优化。本文将系统拆解MySQL中5种核心关联查询算法,结合实战案例分析适用场景,并总结可落地的优化策略。

一、关联查询的核心算法总览

MySQL的关联查询本质是“驱动表”与“被驱动表”的匹配过程,不同算法的差异体现在“如何高效匹配两表数据”。先通过一张表快速掌握各算法的核心逻辑:

Join算法核心原理适用场景关键优势/劣势
Simple Nested-Loop Join驱动表每行→被驱动表全表扫描匹配无(MySQL未实际采用)逻辑简单,扫描行数m*n,效率极低
Index Nested-Loop Join驱动表每行→通过索引定位被驱动表匹配数据被驱动表关联字段有索引扫描行数少,依赖索引效率
Block Nested-Loop Join驱动表数据批量写入join_buffer→被驱动表每行与缓冲区数据对比MySQL 8.0.20前,被驱动表无索引减少全表扫描次数,依赖缓冲区大小
Hash Join驱动表构建哈希表→被驱动表逐行通过哈希函数匹配MySQL 8.0.20后,被驱动表无索引减少IO,比BNL更省资源
Batched Key Access驱动表数据批量入join_buffer→MRR接口排序主键→批量匹配被驱动表索引被驱动表有索引,大数据量关联批量处理+顺序IO,效率最优

二、逐个拆解:5种Join算法的原理与实战

2.1 被淘汰的“基础款”:Simple Nested-Loop Join

原理

最朴素的关联逻辑:遍历驱动表(数据量m)的每一行,都去被驱动表(数据量n)做全表扫描,满足条件则返回结果。
扫描总行数 = m * n,若两表均为1万行,需扫描1亿次,性能极差。

关键结论

MySQL未实际采用该算法——即使被驱动表无索引,也会用Block Nested-Loop Join或Hash Join优化,此算法仅作为理解其他算法的基础。

2.2 索引依赖型:Index Nested-Loop Join(NLJ)

原理

被驱动表的关联字段有索引时,MySQL优先选择NLJ,流程如下:

  1. 选择“小表”作为驱动表(减少外层循环次数);
  2. 遍历驱动表每行,提取关联字段值;
  3. 通过关联字段的索引,快速定位被驱动表的匹配行;
  4. 合并两表结果返回。

实战案例

1. 准备测试数据

-- 创建表t1(1万行)和t2(100行,小表)
use martin; 
drop table if exists t1; 
CREATE TABLE `t1` (
  `id` int NOT NULL auto_increment,
  `a` int DEFAULT NULL,
  `b` int DEFAULT NULL,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_a` (`a`) -- 关联字段a建索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入1万行数据
drop procedure if exists insert_t1;
delimiter ;;
create procedure insert_t1()
begin
declare i int; set i=1;
while(i<=10000)do
insert into t1(a,b) values(i, i); set i=i+1; 
end while;
end;;
delimiter ; 
call insert_t1();
-- 复制t1为t2,仅保留100行(小表)
drop table if exists t2; 
create table t2 like t1; 
insert into t2 select * from t1 limit 100;

2. 执行关联查询并分析计划

explain select * from t1 inner join t2 on t1.a = t2.a;

执行计划关键信息

  • 驱动表是t2(小表,explain第一行),被驱动表是t1
  • Extra字段无“Using join buffer”,说明使用NLJ算法;
  • 被驱动表通过idx_a索引匹配,扫描行数极少。

关键结论

  • NLJ的效率核心依赖被驱动表的索引,无索引则无法使用;
  • 驱动表选择“小表”可减少外层循环次数,优化器默认会自动选择小表作为驱动表(可通过straight_join强制指定)。

2.3 无索引方案1:Block Nested-Loop Join(BNL)

原理

被驱动表无索引且MySQL版本≤8.0.19时,采用BNL算法,核心是“批量匹配减少IO”:

  1. 将驱动表数据批量写入join_buffer(默认大小256KB,可通过join_buffer_size调整);
  2. 遍历被驱动表每行,与join_buffer中所有驱动表数据对比;
  3. 满足条件则返回结果。

实战案例

-- 关联字段b无索引(t1、t2的b字段均未建索引)
explain select * from t1 inner join t2 on t1.b = t2.b;

MySQL 5.7执行计划关键信息

  • Extra字段显示“Using join buffer (Block Nested Loop)”,确认使用BNL;
  • 扫描行数 = 驱动表行数 + 被驱动表行数(批量匹配减少了全表扫描次数)。

关键结论

  • BNL比Simple Nested-Loop Join效率高,但仍需扫描被驱动表全表;
  • join_buffer_size过小时,驱动表会分批次写入缓冲区,导致被驱动表多次全表扫描,需合理调整。

2.4 无索引方案2:Hash Join(MySQL 8.0.20+)

原理

MySQL 8.0.20起,用Hash Join替代BNL,核心是“哈希表快速匹配”:

  1. 将驱动表数据加载到内存,构建“关联字段→行数据”的哈希表;
  2. 逐行读取被驱动表,通过哈希函数计算关联字段的哈希值;
  3. 查找哈希表中匹配的哈希值,对比原始数据后返回结果。

实战对比

同上述BNL案例,在MySQL 8.0.25中执行:

explain select * from t1 inner join t2 on t1.b = t2.b;

执行计划关键信息

  • Extra字段显示“Using join buffer (hash join)”,确认使用Hash Join;
  • 无需将被驱动表数据写入磁盘/内存,IO次数比BNL更少,性能提升30%+。

关键结论

  • Hash Join是无索引场景下的最优选择,建议将MySQL升级至8.0.20+;
  • 若驱动表过大,哈希表会溢出到磁盘,需通过join_buffer_size确保哈希表在内存中。

2.5 性能天花板:Batched Key Access(BKA)

原理

BKA是NLJ的优化版,结合“批量处理”与“顺序IO”,需满足被驱动表有索引,流程如下:

  1. 驱动表数据批量写入join_buffer
  2. 批量将关联字段值发送到MRR(Multi-Range Read)接口;
  3. MRR按主键排序关联字段对应的主键ID,减少随机IO;
  4. 按排序后的主键批量读取被驱动表数据,匹配后返回。

如何开启BKA

BKA需手动开启MRR相关参数:

-- 开启MRR和BKA
set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
-- 验证BKA是否生效
explain select * from t1 inner join t2 on t1.a = t2.a;

执行计划关键信息

  • Extra字段显示“Using join buffer (Batched Key Access)”,确认BKA生效;
  • 批量处理减少索引查询次数,MRR排序减少随机IO,大数据量下比NLJ快2-5倍。

三、关联查询优化:4个核心策略

1. 关联字段必须加索引

这是最核心的优化!将“无索引场景”(BNL/Hash Join)转化为“有索引场景”(NLJ/BKA),性能提升可达10倍以上。
案例对比

  • 无索引(BNL):select * from t1 join t2 on t1.b=t2.b,耗时0.08秒;
  • 有索引(NLJ):select * from t1 join t2 on t1.a=t2.a,耗时0.01秒。

2. 强制选择小表作为驱动表

当优化器选择错误时(如统计信息过时),用straight_join强制指定小表为驱动表:

-- 强制t2(小表)为驱动表
select * from t2 straight_join t1 on t2.a = t1.a;

3. 大数据量用BKA优化

对于百万级以上数据的关联查询,开启BKA可大幅减少IO次数,尤其适合“驱动表大、被驱动表有索引”的场景。

4. 升级MySQL至8.0.20+

用Hash Join替代BNL,无索引场景下性能提升30%+,同时减少资源占用。

四、总结

MySQL关联查询的效率,本质是“算法选择”与“资源利用”的平衡:

  • 有索引优先用BKA/NLJ,核心是“索引+小表驱动”;
  • 无索引优先用Hash Join(8.0.20+),避免BNL的高IO;
  • 大数据量必开BKA,通过批量处理和MRR优化IO。

掌握这些算法原理与优化策略,可轻松应对90%以上的MySQL关联查询性能问题。

到此这篇关于MySQL Join关联查询的几种实现方式优化小结的文章就介绍到这了,更多相关MySQL Join关联查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mysql如何分组统计并求出百分比

    mysql如何分组统计并求出百分比

    这篇文章主要介绍了mysql如何分组统计并求出百分比,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 详解Mysql 30条军规

    详解Mysql 30条军规

    这篇文章主要介绍了详解Mysql 30条军规,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • mysql通过binlog定时备份数据库与恢复的方法

    mysql通过binlog定时备份数据库与恢复的方法

    这篇文章主要介绍了mysql通过binlog定时备份数据库与恢复的方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • MySQL数据库语句完全讲解

    MySQL数据库语句完全讲解

    MySQL作为最流行的开源关系型数据库,其查询语句涵盖了从基础数据检索到复杂多表关联的全场景需求,这篇文章主要介绍了MySQL数据库语句的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-01-01
  • Mysql插入带有引号的字符串数据最佳实践

    Mysql插入带有引号的字符串数据最佳实践

    在MySQL中可以使用单引号或双引号来包裹字符串,下面这篇文章主要给大家介绍了关于Mysql插入带有引号的字符串数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • 不确定mysql是否安装成功了的检查办法(Windows、Linux、macOS)

    不确定mysql是否安装成功了的检查办法(Windows、Linux、macOS)

    MySQL安装完成后,需通过命令行操作和服务状态检查确认安装是否成功,这篇文章主要介绍了各系统(Windows、Linux、macOS)下不确定mysql是否安装成功了的检查办法,需要的朋友可以参考下
    2026-02-02
  • MySQL 元数据查看及实例代码

    MySQL 元数据查看及实例代码

    这篇文章主要介绍了MySQL 元数据查看及实例代码的相关资料,需要的朋友可以参考下
    2017-01-01
  • MySQL max_allowed_packet的坑

    MySQL max_allowed_packet的坑

    max_allowed_packet是 MySQL 中的一个设定参数,用于设定所接受的包的大小,根据情形不同,其缺省值可能是 1M 或者 4M,本文主要介绍了MySQL max_allowed_packet的坑,感兴趣的可以了解一下
    2024-01-01
  • MySQL Innodb 存储结构 和 存储Null值 用法详解

    MySQL Innodb 存储结构 和 存储Null值 用法详解

    这篇文章主要介绍了MySQL Innodb 存储结构 和 存储Null值 用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • MySQL InnoDB架构的相关总结

    MySQL InnoDB架构的相关总结

    InnoDB存储引擎架构作为MySQL最常用的存储引擎,每个后端程序员都应有所了解,本文将具体讲述MySQL InnoDB架构的相关知识,感兴趣的朋友可以参考下
    2021-05-05

最新评论