mysql如何优化order by查询_mysql排序优化技巧

来源:这里教程网 时间:2026-02-28 20:51:15 作者:

ORDER BY 没走索引?先看执行计划里的
Using filesort

只要

EXPLAIN
结果中出现
Using filesort
,就说明 MySQL 没法用索引直接完成排序,得把数据捞出来再内存或磁盘排序——这是性能瓶颈的明确信号。

常见诱因包括:

ORDER BY
字段没建索引,或索引不匹配(比如复合索引
(a, b)
,却只按
b
排序)
查询里混用了
SELECT *
ORDER BY
,导致覆盖索引失效
WHERE
条件用了范围查询(如
a > 100
),之后的索引字段无法用于排序
排序字段类型与索引字段类型不一致(比如索引是
VARCHAR(50)
ORDER BY
却隐式转成
VARCHAR(10)

复合索引怎么建才让 ORDER BY 走索引?

核心原则:索引顺序 =

WHERE
等值条件字段 +
ORDER BY
字段(且不能有范围条件隔开)。

例如查询:

SELECT id, name FROM users WHERE status = 1 ORDER BY created_at DESC

应建索引:

INDEX (status, created_at)
—— 这样能同时满足过滤和排序。

注意这些细节:

如果
ORDER BY
created_at ASC, id DESC
,索引也得严格对应方向(MySQL 8.0+ 支持混合方向,但 5.7 只支持全 ASC 或全 DESC)
WHERE
中有多个等值条件(
status = 1 AND type = 'vip'
),索引字段顺序不影响过滤效率,但建议把高频过滤字段放前
避免在索引里包含太多字段,尤其是大字段(如
TEXT
),会拖慢写入和索引体积

分页深翻(OFFSET 大)为什么慢?用游标替代

LIMIT 10000, 20
慢,不是因为取 20 行,而是 MySQL 必须先扫描前 10000 行并丢弃——即使有索引,也是“跳着扫”。

更优解是游标分页(cursor-based pagination):

首次查:
SELECT id, name, created_at FROM posts ORDER BY created_at DESC LIMIT 20
下一页传上一页最后一条的
created_at
id
SELECT id, name, created_at FROM posts WHERE created_at 
关键点:WHERE 条件必须能利用索引,ORDER BY 字段必须是索引前缀

临时表排序撑爆内存?调小
sort_buffer_size
反而更快

很多人以为把

sort_buffer_size
调大就能加速排序,实际容易适得其反:单个连接独占该内存,设太大反而导致并发时内存争抢、触发 swap。

合理做法:

线上环境一般设为
2M~4M
(默认通常是 256K,太小会导致频繁磁盘排序)
确认是否真需要全局调大:先用
SHOW PROFILE FOR QUERY N
Sorting result
阶段耗时占比
更治本的是减少参与排序的数据量——加更精准的
WHERE
条件,或改用覆盖索引避免回表

真正卡住的往往不是排序本身,而是排序前没过滤干净的数据流。索引设计和查询写法,比调参重要得多。

相关推荐