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

相关推荐
上学的小垃圾9 小时前
01-数据库系统概述
数据库
二进制漫游记10 小时前
FastAPI项目集成 Qdrant向量数据库+阿里云Embedding完整实战(工具封装+业务调用)
数据库·python·阿里云·embedding
2501_9289962210 小时前
GPT-4o换DeepSeek迁移成本多少?中科热备解析API聚合平台技术账本
前端·数据库·人工智能
泡干脆面就番茄12 小时前
MySQL_子查询_分页查询与联合查询详解
数据库·mysql
devpotato13 小时前
缓存与数据库更新顺序不一致问题
java·数据库·redis
天若有情67313 小时前
Node+MySQL小型全栈笔记项目实战课程分享
数据库·笔记·mysql
wxwx_bscxy32214 小时前
基于springboot宠物领养系统的设计与实现
数据库·spring boot·后端·spring·宠物
九月要晚安14 小时前
达梦DW与AFC对比
数据库
实战派K8S&DB15 小时前
如何在内网配置 TiDB 数据库 Agent
数据库·人工智能·分布式·tidb
实战派K8S&DB15 小时前
《基于 Dify + FastAPI + PyTiDB 搭建大模型驱动的 TiDB 智能运维 Agent》
运维·数据库·分布式·云原生·tidb·fastapi