索引的排序和分组

先把前提说清楚:

表有两个索引:

  • 联合索引: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 单列索引。
相关推荐
白远山23 分钟前
货运跑腿搬家平台开发实战:从需求分析到落地部署指南
数据库·数据挖掘·需求分析
geovindu35 分钟前
sql: Data Modeling Patterns
数据库·sql·设计模式·sqlserver
上海蓝色星球42 分钟前
蓝色星球NG-AIOS新型AI工业操作系统重磅发布——以本体智能为内核,重构“AI+制造“新范式
大数据·数据库·人工智能·机器人
瀚高PG实验室1 小时前
瀚高数据库如何克隆表
数据库·sql·postgresql·瀚高数据库
雨辰AI1 小时前
信创多租户项目 9 大踩坑|数据隔离失效、权限越权终极解决(金仓 / 达梦 / 高斯全库适配)
java·大数据·数据库·后端
严同学正在努力1 小时前
认识 SQL Server 的 T-SQL 语法
数据库·人工智能·ai·oracle·dba
EatFan1 小时前
我为什么把患者与病例从 1:1 改成 1:N?一次真实数据库模型重构记录
数据库·后端·重构·健康医疗·全栈
xujuzheng2 小时前
2026深圳小程序/App/AI智能体开发公司选型指南(附本地服务商盘点)
数据库·科技·微信小程序·小程序·uni-app
bksczm2 小时前
MySQL基础篇之表的增删查改(CRUD)细则
sql·mysql
不剪发的Tony老师2 小时前
DuckDB教程:常用文本函数
数据库·sql·数据分析·duckdb