【MySQL-索引调优】09:Order By相关概念

PS:现在orders表中存在idx_user_id(user_id),idx_user_status(user_id, status),idx_remark(remark)三个索引,表数据量为10w行

1-where + order by

运行:

sql 复制代码
EXPLAIN SELECT * FROM orders WHERE user_id = 1 ORDER BY create_time;

结果为:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE orders ref idx_user_id,idx_user_status idx_user_id 9 const 9 100 Using filesort

分析:

  • key = idx_user_id :查询条件user_id = 1用到了user_id索引,能快速定位到该用户的所有订单
  • rows = 9:预估只需要扫描9行,说明索引过滤效果很好
  • Extra = Using filesort :这是重点:虽然索引帮你定位到了user_id=1的行,但排序字段是create_time,而这个字段不在索引里,所以 MySQL 需要额外做一次排序操作(filesort)。 "filesort"并不是一定写到磁盘,它可能在内存里完成,但总之是额外的排序步骤

如果后续优化的话,可以加上联合索引(user_id, create_time)

2-单独order by

运行:

sql 复制代码
EXPLAIN SELECT * FROM orders ORDER BY create_time;

结果为:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE orders ALL 99520 100 Using filesort

分析:

(create_time)没有索引,所以具体的流程是:

复制代码
全表扫描
   ↓
取出99520行
   ↓
按 create_time 排序

本质就是create_time字段排序了,还是要建立索引提高性能

3-order by + limit

常用Sql:

sql 复制代码
SELECT *
FROM orders
ORDER BY create_time DESC
LIMIT 20;

看起来只查:

复制代码
20条

但数据库仍然要:

复制代码
扫描全部数据
→ 排序全部数据
→ 取20条

还是要排序

4-order by + limit分页:

Sql:

sql 复制代码
SELECT *
FROM orders
ORDER BY create_time
LIMIT 10000, 10;

很多人以为数据库会:

复制代码
直接跳到第10000条
取10条

4-1.无索引的情况

ORDER BY create_time 会触发 全表扫描 + 排序

数据量大时,排序需要额外的内存或磁盘临时空间(sort buffer / external sort)。

然后再应用 LIMIT 10000,10,意味着先排好所有 10w 行,再丢掉前 10000 行,只取 10 行。

复制代码
1. 扫描全表 10w 行(读取所有数据到内存)
2. 对 10w 行进行快速排序(O(N log N))
3. 取排序后的第 10001-10010 行
4. 返回 10 行

4-2.有create_time索引的情况

索引本身就是按 create_time 排序的(B+Tree)

查询可以直接在索引上顺序扫描,不需要额外排序

但是 LIMIT 10000,10 依然意味着要 从索引头开始扫描到第 10010 行,然后返回第 10001~10010 行

复制代码
1. 从索引树根节点开始,按 create_time 顺序遍历
2. 跳过前 10000 个索引条目(仍需"数"过去,但只读索引)
3. 取第 10001-10010 个索引条目
4. 根据这 10 个 id 回表取完整数据
5. 返回 10 行

所以优化点在于:省掉了排序操作,但不能跳过前 10000 行的扫描

4-3.总结

无索引:全表排序 → 丢弃前 10 000 → 取 10

有索引:索引顺序扫描 → 丢弃前 10000 → 取 10

优化效果:索引省掉了排序操作,因为索引本质就是排序的(B+Tree),避免了昂贵的排序,但 offset 大时仍然会有性能问题,因为要扫描很多行

PS:

  • 无索引情况,性能最差,直接用表数据(相当于全表访问)
  • 有索引,扫描到第 10010 行,仅回表10次
相关推荐
吠品1 小时前
.NET 8 单文件发布:把 exe 和一堆 dll 打进一个文件里
服务器·数据库·windows
cmes_love1 小时前
期货五档tick数据下载教程期权五档高频历史数据以及分钟量化回测下载
数据库
蚂蚁数据AntData1 小时前
从ChatBI到业务记忆:重新定义数据智能的生产力边界
大数据·网络·数据库·人工智能·算法
cfm_29141 小时前
JVM垃圾收集算法与收集器深度解析
jvm·测试工具·算法·性能优化
Quincy_Freak1 小时前
技术随笔|银河麒麟aarch64内网轻量数据分析工具 SQLiteGo 使用体验
大数据·数据库·数据挖掘·数据分析·sqlite·银河麒麟·aarch64
Amnesia0_01 小时前
MySQL视图和用户管理
数据库·mysql
matrixmind12 小时前
aiomysql:异步场景下的 MySQL 驱动
android·数据库·mysql·其他
数据库小学妹2 小时前
时序数据怎么存?InfluxDB、TDengine、TimescaleDB与国产融合方案选型实战
大数据·数据库·经验分享·时序数据库·dba
芒鸽2 小时前
HarmonyOS 数据持久化开发实战:KVStore、关系型数据库与 Preferences
数据库·华为·harmonyos
kisdiem2 小时前
让大模型从“会回答”走向真正调用业务系统
数据库