记录一下那天晚上的排查过程。后台导出按页拉数据,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。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
