记录一下那天晚上的排查过程。后台导出按页拉数据,limit 100000,20 这一页要十秒,前几页都很快,表里两千万行,MySQL 8.0 默认配置,导出任务一共要翻五千页。

刚开始盯着「select 取了 text 大字段,回表代价被放大」,折腾了半个多小时,排掉了。

这类报错背后常见的原因有几处,逐个排除就行。偏移量越大,被丢弃的行越多,扫描成本线性增长。另一种情况是排序字段和主键不一致,每页都要重新排一遍。

还有一种情况,查询条件没走覆盖索引,每次都要回表取列。

上来先确认扫描行数随偏移量增长的趋势

mysql -e "explain select * from orders order by id limit 100000,20\G"

接着改成基于游标的写法

mysql -e "select id,order_no from orders where id > 100000 order by id limit 20;"

只取主键再回表拿字段

mysql -e "select o.* from orders o join (select id from orders order by id limit 100000,20) t on o.id=t.id;"

剩下的就是导出场景改按主键区间分段

mysqldump --where='id between 1 and 100000' shop orders > part1.sql

别只看报错消失,验证要多做一步。游标写法在任意页码下耗时都在三十毫秒内,导出任务整体时间从两小时降到二十分钟。

这里还有个坑。深分页本质是数据库要先读出再丢掉,靠索引救不了偏移量本身;业务上能改成游标或者按时间分区就别硬优化 SQL。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189