MySQL索引排序要求ORDER BY字段为索引最左前缀且方向一致,否则触发Using filesort;深度分页应改用游标分页;索引设计优先满足ORDER BY而非WHERE;ORDER BY RAND()需避免。
ORDER BY 字段必须是索引最左前缀才能走索引排序
MySQL 只有在 ORDER BY 的字段顺序和索引定义完全匹配(或为最左前缀)时,才能利用索引完成排序,避免 Using filesort。否则即使 WHERE 条件走了索引,排序仍会触发临时文件排序,性能陡降。
- 假设有复合索引
INDEX idx_status_created (status, created_at),则WHERE status = 1 ORDER BY created_at可走索引排序;但WHERE status = 1 ORDER BY id不行,id不在索引中 -
ORDER BY created_at DESC, status ASC也不行——方向不一致且顺序错位,MySQL 8.0+ 虽支持混合方向索引,但需显式创建如INDEX(... ASC, ... DESC) - 用
EXPLAIN看Extra列:出现Using index; Using filesort表示用了覆盖索引但没躲开排序;只有Using index才表示排序也由索引完成
LIMIT 配合索引排序时,避免“深度分页”陷阱
当写 ORDER BY created_at LIMIT 10000, 20,MySQL 仍要定位前 10000 行再取 20 行,导致越往后越慢。这不是 LIMIT 本身的问题,而是排序 + 偏移的组合代价高。
- 改用游标分页(cursor-based pagination):记录上一页最后一条的
created_at值,下一页查WHERE created_at > '2024-01-01 10:00:00' ORDER BY created_at LIMIT 20 - 如果必须用 offset,确保
ORDER BY字段有高选择性且索引覆盖,否则优化器可能放弃索引而走全表扫描 - 注意:InnoDB 的聚簇索引主键顺序会影响排序效率;若按非主键排序且无合适索引,即使加了 LIMIT,执行计划仍可能显示
rows极大(只是提前终止)
WHERE + ORDER BY + LIMIT 组合下,索引设计优先满足排序而非过滤
当过滤条件和排序字段都可用索引时,索引字段顺序决定优化效果。MySQL 更倾向复用排序索引做过滤,而不是反过来。