索引的排序和分组

先把前提说清楚:

表有两个索引:

  • 联合索引:idx_abcd (a, b, c)
  • 单列索引:idx_c (c)

你问的两条 SQL:

  1. WHERE b = 1 ORDER BY c不走索引,全表扫描 + filesort
  2. WHERE b = 1 GROUP BY c能用上 idx_c(c 的单列索引)

下面讲透为什么不一样(完全从优化器成本 + 索引结构角度讲)。


一、先说:两条 SQL 都用不了联合索引 (a,b,c)

联合索引要满足最左前缀 :必须从 a 开始,连续向右匹配。

  • 你的条件只有 b=1没有 a
  • 所以:(a,b,c) 直接废掉,两条语句都用不了它

现在只剩一个候选索引:idx_c (c)


二、为什么 WHERE b=1 ORDER BY c 不用 idx_c

语句:

sql 复制代码
WHERE b = 1 ORDER BY c

1. 索引 idx_c 是按 c 排序的,不是按 b

索引结构大概是:

复制代码
c=1 → 行地址
c=2 → 行地址
c=3 → 行地址
...

不按 b 分组/排序

2. 用 idx_c 的执行过程会是:

  • 遍历整个 c 索引(所有 c 值)
  • 每一行都要回表去判断:b 是不是等于 1
  • 筛选完后,结果集还要再按 c 排序(本来 c 有序,但中间被 b 过滤打断,不是连续的)

→ 优化器一算:回表 + 过滤 + 还要排序,成本比全表扫描还高

→ 干脆:放弃索引,直接全表扫描,然后 filesort

一句话:ORDER BY c 需要 c 整体连续有序,但 WHERE b=1 会把 c 的连续顺序"切碎",用 c 索引得不偿失。


三、为什么 WHERE b=1 GROUP BY c 反而能用 idx_c

语句:

sql 复制代码
WHERE b = 1 GROUP BY c

1. GROUP BY 的本质:按 c 去重 + 分组

只要数据按 c 有序,就能:

  • 顺序扫 c 索引
  • 遇到新 c → 开新组
  • 同 c 连续出现 → 合并到同一组

不需要严格"所有行都满足 b=1"再分组,可以边扫边过滤、边分组。

2. 用 idx_c 的执行逻辑(松散/紧凑索引扫描)

  • c 从小到大扫 idx_c
  • 每一行:回表看 b=1
    • 是 → 计入当前 c 组
    • 否 → 跳过
  • c 变了 → 输出上一组,开新组

优点:

  • 天然按 c 有序,不需要 filesort
  • 分组逻辑和索引顺序完美匹配
  • 优化器认为:比全表扫描快

所以:GROUP BY c 能利用 c 索引的有序性,即使 WHERE 有 b 过滤,依然划算。


四、一句话总结(面试直接背)

  • WHERE b=1 ORDER BY c
    c 索引有序被 b 过滤打乱,用索引要大量回表+排序,成本高 → 放弃索引,全表扫描。
  • WHERE b=1 GROUP BY c
    GROUP BY 只需要 c 有序去重分组,可以边扫边过滤,避免 filesort → 选择 c 单列索引。
相关推荐
城管不管4 小时前
重生——第十一次面试之挖财一面2026.8.19已OC
java·服务器·jvm·数据库·spring·面试·职场和发展
倔强的石头1064 小时前
向量数据库从相似度检索走向融合数据底座
数据库
今天AI了吗5 小时前
Python 基础语法(一):常量、变量、输入输出与运算符
开发语言·数据库·人工智能·python·sql·深度学习·机器学习
夜雪一千6 小时前
MySQL 全局锁是什么?原理、风险、备份踩坑完整实战
android·mysql·adb
lilian2336 小时前
Harmony os 技术实战|拼豆制图27:用单字符编码承载 50 张 70×70 图纸
前端·数据库·华为·harmonyos
皮卡丘不断更7 小时前
手机优先的 Personal Ledger:把账目、学习和复盘放到同一个入口
数据库·sqlite·fastapi·开源项目·个人效率
保卫大狮兄8 小时前
设备管理从台账到报废,完整生命周期一次讲清
数据库·设备管理·设备
数据安全技术观察8 小时前
数据动态脱敏:让脱敏策略跟着数据目录走
大数据·网络·数据库
小席是个热心肠9 小时前
Redis的自我学习
数据库·redis·学习
2601_965798479 小时前
Salient Theme Setup Guide for Fast Creative WordPress Sites
数据库·web3·php·wordpress