订单列表接口偶尔要八秒,慢日志里 Rows_examined 是三百万,Rows_sent 只有二十,SQL 按创建时间倒序取第一页,表上只有主键索引。

一开始怀疑是「联合索引的列顺序和 order by 对不上」,查了一圈,方向不对。

原因不止一个,得分开看。排序字段没有索引,只能全表扫完再 filesort。少数情况下是where 里对字段套了函数,索引用不上。

不容易想到的是,统计信息过期,优化器估错了返回行数。

第一件事是看执行计划里的访问类型和额外操作

mysql -e "explain analyze select id,order_no from orders where created_at>='2026-11-01' and created_at<'2026-11-02' order by id desc limit 20\G"

建与过滤排序都匹配的联合索引

mysql -e "alter table orders add index idx_created_id(created_at,id), algorithm=inplace, lock=none;"

接着把函数条件改写成范围条件

mysql -e "explain select id from orders where created_at >= '2026-11-01' and created_at < '2026-11-02' limit 20\G"

更新统计信息后复测耗时

mysql -e "analyze table orders;"

恢复的判定其实很直接。执行计划里访问类型变成 range,filesort 消失,扫描行数降到几百,接口耗时回到五十毫秒以内。

这里还有个坑。扫描行数比返回行数高两个数量级,基本就是索引没吃上;大表加索引放在低峰做,期间的元数据锁会挡住写入。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189