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

相关推荐
陈文锦丫5 小时前
微服务-----
java·数据库·微服务
dishugj5 小时前
[ORACLE]oracle用户密码永不过期修改以及ORA-28000报错解决
数据库·oracle
一点事5 小时前
oracle:存储过程基础语法
数据库·oracle
tebukaopu1485 小时前
mysql distinct慢
数据库·mysql
步步为营DotNet5 小时前
深入理解IAsyncEnumerable:异步迭代的底层实现与应用优化
java·服务器·数据库
数据库学啊6 小时前
专业的国产时序数据库公司
数据库·时序数据库
黑客思维者6 小时前
突破 Python 多线程限制:GIL 问题的 4 种实战解法
服务器·数据库·python·gil
l1t6 小时前
利用Duckdb求解Advent of Code 2025第5题 自助餐厅
数据库·sql·mysql·算法·oracle·duckdb·advent of code
驾数者6 小时前
Flink SQL关联查询:双流Join与维表Join实战技巧
数据库·sql·flink