order by 本身不占 buffer pool,但若触发全表扫描或大范围索引扫描,会大量加载数据页(16kb/页)进入 buffer pool;真正消耗 buffer pool 的是读取的数据页,而非排序动作本身。

Order BY 本身不占 Buffer Pool,但关联的全表扫描会
执行 ORDER BY 查询时,MySQL 是否大量消耗 innodb_buffer_pool_pages_data,关键不在排序动作本身,而在于它是否触发了全表扫描或大范围索引扫描。Buffer Pool 缓存的是数据页(16KB),不是排序结果;只要查询需要读取大量磁盘页,这些页就会被加载进 Buffer Pool。
常见错误场景包括:
- WHERE 条件没走索引,
ORDER BY字段虽有索引,但优化器仍选择全表扫描 + filesort - 联合索引设计不合理,比如建了
INDEX idx_a (a)却执行WHERE b = ? ORDER BY a,导致无法利用索引覆盖 - 使用
ORDER BY RAND()或未加 LIMIT 的宽泛排序,迫使 MySQL 加载远超实际返回行数的数据页
sort_buffer_size 和 Buffer Pool 是两套独立内存系统
sort_buffer_size 是线程私有缓冲区,分配在 Server 层,不计入 innodb_buffer_pool_pages_data 统计;它的内存来自每个连接的线程堆空间,大小默认 256KB~2MB。而 Buffer Pool 是 InnoDB 引擎层的共享内存池,只缓存数据页和索引页。
所以你看到 Created_tmp_tables 上升、Sort_merge_passes 增多,说明排序内存不足,但 Buffer Pool 使用量可能纹丝不动——这两者压根不共用同一块内存。
容易混淆的点:
-
SHOW ENGINE INNODB STATUS里Buffer pool hit rate低,大概率是 SQL 没走索引,而不是排序本身导致 -
innodb_buffer_pool_reads持续上涨 +innodb_buffer_pool_read_requests稳定,说明大量物理读,根源在查询范围过大 - 调大
sort_buffer_size可能缓解Out of sort memory错误,但对 Buffer Pool 占用无直接影响
真正让 Buffer Pool 被“撑爆”的 Order BY 场景
当 ORDER BY 查询被迫回表、或配合子查询/临时表时,才可能间接推高 Buffer Pool 使用。典型路径是:ORDER BY → 触发 filesort → 需要读取完整行 → 若 SELECT * 或含大字段(如 JSON、TEXT),InnoDB 就得把整行所在的数据页都加载进来 —— 即使只返回 10 行,也可能拉入几百个页。
更隐蔽的问题:
- 使用前缀索引(如
INDEX idx_title (title(100)))后,ORDER BY title无法利用索引排序,必须回表取完整字段,放大 Buffer Pool 压力 - JSON 字段参与排序(MySQL 8.0.20+):排序时会将整个 JSON 值解构并暂存内存,若该字段在数据页中分散存储,可能触发额外页读取
-
GROUP BY ... ORDER BY复合操作未被索引覆盖,MySQL 先建临时表再排序,临时表内容若落盘(Created_tmp_disk_tables),其元数据和部分缓存页仍会驻留 Buffer Pool
查证与定位:别只盯 explain 的 “Using filesort”
仅靠 EXPLAIN 输出里的 Using filesort 无法判断 Buffer Pool 是否过载。你需要交叉验证三组指标:
- 看
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads'是否随该类查询陡增 - 用
SELECT table_name, index_name, sum_number_of_pages FROM information_schema.INNODB_BUFFER_PAGE WHERE table_name = 'your_table' GROUP BY table_name, index_name ORDER BY sum_number_of_pages DESC查哪张表/哪个索引实际占着 Buffer Pool - 对比
Handler_read_first(索引首次扫描)和Handler_read_rnd(随机回表读):若后者远高于前者,说明排序引发大量非顺序 IO,Buffer Pool 压力来自回表而非排序逻辑本身
最常被忽略的一点:Buffer Pool 里堆积的,往往不是你要排序的那几行,而是它们所在的整个数据页——哪怕一页里只有 1 行被用到,另外 15KB 也得一起搬进来。











