mysql8 loose index skip scan 特性加速分组查询性能

前言

要理解Loose Index Scan(松散索引扫描) 如何加速 GROUP BY,核心是抓住「索引有序性 」和「跳过无效数据、只取分组核心值」这两个关键点------它彻底避开了"遍历所有数据→临时表分组"的低效路径,直接从有序索引中"精准提取"分组结果。

先看「常规 GROUP BY」的低效逻辑(对比更易理解)

假设表 t1 有索引 idx(c1,c2),数据如下(索引是有序存储的,所以实际索引中 c1 的值是连续的):

c1 c2
1 10
1 20
2 30
2 40
3 50

如果执行 SELECT c1, MIN(c2) FROM t1 GROUP BY c1;常规方式的执行步骤是:

  1. 扫描全表(或全索引),读取所有 5 行数据;
  2. 创建临时表,把 c1=1 的两行、c1=2 的两行、c1=3 的一行分别归集;
  3. 对每个分组计算 MIN(c2)
  4. 返回结果。

这个过程要遍历所有数据,还需要临时表,数据量越大效率越低。

再看「Loose Index Scan」的加速逻辑

因为索引 idx(c1,c2)有序的 (BTREE 索引特性),c1 相同的记录在索引中是连续排列的。Loose Index Scan 利用这一点,只读取每个分组的"关键值",跳过同分组的其他数据

步骤拆解(还是上面的查询 SELECT c1, MIN(c2) FROM t1 GROUP BY c1;):

  1. 定位索引中第一个 c1=1 的记录,其 c2=10------因为索引有序,同组后续的 c1=1 记录的 c2 一定≥10,所以 MIN(c2) 直接确定为 10,无需读取 c1=1 的下一条记录(c2=20)
  2. 跳过所有 c1=1 的剩余记录,直接定位到第一个 c1=2 的记录,其 c2=30------同理,MIN(c2)=30,跳过 c1=2 的下一条记录(c2=40);
  3. 跳过所有 c1=2 的剩余记录,定位到第一个 c1=3 的记录,其 c2=50------MIN(c2)=50
  4. 直接返回结果,全程只读取了 3 条记录(每个分组 1 条),且无需创建临时表

核心加速点总结:

维度 常规 GROUP BY Loose Index Scan
数据读取量 遍历所有符合条件的记录 仅读取每个分组的"首条关键记录"
临时表 必须创建(归集分组) 无需创建
计算逻辑 先归集所有数据,再算聚合 直接从索引首条记录推导聚合结果
时间复杂度 O(N)(N 为总记录数) O(M)(M 为分组数,M << N)

再举一个带范围条件的例子,更显"松散"的优势

如果查询是 SELECT c1, MIN(c2) FROM t1 WHERE c1 < 3 GROUP BY c1;

  • 常规方式:读取 c1<3 的所有 4 条记录(c1=1 的 2 条 + c1=2 的 2 条),临时表分组后计算;
  • Loose Index Scan:仅读取 c1=1 的第一条、c1=2 的第一条,共 2 条记录,直接得出结果,跳过了同组的其他 2 条记录。

为什么叫"松散"?

"松散"的核心是------它不"紧密"遍历索引的每一个键值,而是跳过同分组的所有冗余记录,只抓每个分组的"锚点"(首条记录),就像从有序的数组中"跳着找"分组,而非逐个遍历。

关键前提:为什么能"跳着找"?

必须满足「GROUP BY 列是索引最左前缀」+「聚合函数仅 MIN/MAX 且列紧跟分组列」,本质是:

  1. 索引有序性保证了"同分组的记录连续",所以首条记录就能确定 MIN/MAX;
  2. 索引最左前缀保证了"分组列在索引中是最优先的排序维度",能直接按分组列跳着定位。

如果不满足这些条件(比如用 SUM、GROUP BY 列不是最左前缀),就无法"跳着找",只能退化为 Tight Index Scan 或常规方式。

简单总结:Loose Index Scan 把 GROUP BY 的执行成本,从「依赖数据总量」降到了「依赖分组数量」,分组数远小于数据量时,加速效果极其显著。

官方文档

https://dev.mysql.com/doc/refman/8.0/en/group-by-optimization.html

相关推荐
全栈老石3 小时前
拆解低代码引擎核心:元数据驱动的"万能表"架构
数据库·低代码
倔强的石头_1 天前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou642 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
于眠牧北2 天前
MySQL的锁类型,表锁,行锁,MVCC中所使用的临键锁
mysql
李广坤3 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
Turnip12024 天前
深度解析:为什么简单的数据库"写操作"会在 MySQL 中卡住?
后端·mysql
爱可生开源社区4 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1774 天前
《从零搭建NestJS项目》
数据库·typescript
加号35 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏5 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker