列表翻页第二页又出现上一页最后一条,前端按主键去重就能先上线吗?
结论:列表按创建时间倒序翻页,第二页又出现上一页最后一条,常见根因不是 LIMIT 或 OFFSET 算错,而是 ORDER BY 的排序字段有大量重复值,数据库对同值行不承诺稳定顺序。前端按主键去重只能遮住重复展示,遮不住漏记录。按 2026 年交付经验,在排序末尾补唯一主键多数可稳定;深翻页或无限滚动再考虑游标分页;导出对账类用快照分页。适用边界是十万行以上、排序字段重复多且持续写入的列表;几千行以内且排序键唯一的内部列表,通常不必为此改造。
翻页重复,先看排序字段是不是撞值
分页查询常见写法是 ORDER BY create_time DESC LIMIT 20 OFFSET 20。数据库先按 create_time 排序,再跳过前 20 行取 20 行。当多行 create_time 完全相同时,数据库只保证它们排在一起,并不保证每次返回时这些同值行之间的先后顺序一致。翻到第二页时,上一页末尾的同值行可能又被排到第二页开头,于是出现重复;反过来也可能被跳过,造成漏记录。数据量小、并发写入少时不容易暴露;到几十万行、同一秒或同一分钟创建多条记录时更常见。2026 年项目评审列表接口时,先确认排序键是否唯一,比上线后补更省事。
怎么核对:排序不稳定、数据真重复还是前端缓存?
不要一看到翻页重复就加缓存或换方案。先做几组低成本核对,常见区间半小时到半天可定位。
- 连续执行两次同一页 SQL:参数不变,比较返回主键集合;两次不一致时,排序不稳定的嫌疑较大。
- 查排序字段重复度:对 create_time 等字段分组计数,看是否存在大量相同值。
- 临时在末尾追加主键:改成 ORDER BY create_time DESC, id DESC,再连续翻十页比对。
- 看执行计划:确认是否出现 filesort、索引是否合适,再决定改 SQL 还是改索引。
- 模拟并发写入:一边翻页一边插入,观察重复和遗漏是否集中在页边界。
合格口径可定为:同一列表连续翻十页,主键集合不重复不遗漏;调整排序方向后仍可复现。若仍对不上,再查数据重复写入或前端、接口缓存。
补唯一列、游标分页、快照分页怎么取舍
三类做法不是越复杂越好。按 2026 年常见交付习惯,先看列表用途:后台可跳页、App 无限滚动、导出对账,对应不同方案。下面成本均为经验区间,会随存量代码和索引情况浮动。
- 补唯一列:ORDER BY create_time DESC, id DESC。改动小,实施常见区间约 0.5~1 人天;适合中小数据量、需要跳页的后台列表。限制是大 OFFSET 深翻页仍会慢,数据到百万级后要配合其他手段。
- 游标分页:用上一页最后一条的 create_time 和 id 作为下一页起点,例如 WHERE (create_time, id) < (上一页值)。翻页性能较稳,常见区间约 1~3 人天;适合无限滚动、时间流列表。限制是不能直接跳到第 N 页,产品上要接受上一页或下一页。
- 快照分页:先把满足条件的 id 集合落到临时表或缓存,再按 id 分批取数。结果可核对,常见区间约 3~5 人天;适合后台导出、对账这类一次性批量场景。限制是存储和失效逻辑复杂,不适合高频前台列表。
多数业务列表先补唯一列即可缓解重复;对深翻页性能有要求再升级游标。不要为了跳页需求硬上游标,也不要长期用大 OFFSET 撑导出。
适用与不适用边界
- 适合处理:单表分页结果在十万行以上;排序字段重复值多;列表持续写入;用户反馈过翻页重复或漏数据;后台分页需要稳定对账。
- 不必大动:数据量几千行以内;排序字段本身唯一,如自增主键或唯一单号;只查前几页且不做深翻页;内部临时列表对重复不敏感。
- 不适合只靠前端去重:前端去重只能遮住重复展示,挡不住漏记录,翻页总数和统计值仍可能对不上。
- 不适合上快照分页:高频访问的前台列表、数据变化快的场景,临时快照失效成本高,可能带来新的不一致。
交付现场:前端去重先上线,为什么又返工
有个后台订单列表项目,预算和周期压得紧,团队先让前端按主键去重上线,第二页重复表面上看不见了。但随后运营导出对账,仍发现部分订单漏在页边界;数据从几万涨到百万后,列表继续用大 OFFSET,翻页也变慢。后来补了 id 排序并改成游标接口,前后多花约 1~3 人天。经验区间是:上线前留半天到一天核对排序键唯一性和翻页边界,通常比事后补更省成本。
常见问题
排序字段有重复值,只加 id 排序能解决翻页重复吗?
多数列表能明显缓解。在 ORDER BY 末尾追加唯一主键并保持方向一致,可让同值行有确定顺序,成本也低;数据量很大时再考虑游标分页。
数据量只有几千行,也会第二页重复吗?
可能,但概率通常不高。数据量小、写入少时执行计划较稳定;若排序字段重复多且并发写入,仍建议补唯一列,核对成本也不高。
游标分页能不能做成跳到第 10 页?
不直接支持。游标分页通常只给上一页和下一页锚点,跳页要额外维护页边界或改用快照,产品上需提前确认。
已经补了唯一排序,翻页偶尔还是重复怎么办?
先查前端缓存或接口缓存是否返回旧页,再核对排序方向是否一致、联合索引是否生效;唯一排序解决数据库层不稳定,不解决缓存层脏数据。
后台导出对账漏数据,选哪个方案?
导出类通常更适合快照分页:先把满足条件的 id 固定再分批取,避免导出过程中数据变化;成本比补排序高,但结果便于核对。
结论可带回列表接口评审:先确认排序键是否唯一,再决定补唯一列、游标分页还是快照分页。适用边界是十万行以上、排序字段重复多且持续写入的列表;几千行以内且排序键唯一的内部列表,不必为此大改。交付前按常见区间留半天到一天做翻页核对,通常比上线后返工更省成本。
-
订单列表滚到很后面就转圈,offset 越大越慢,能不能只把每页条数调小?
日期:2026年9月29日 阅读:68
-
运营每周都要改活动开关,每次都找研发发版,配置该不该挪到配置中心?
日期:2026年10月14日 阅读:69
-
上线后 OPTIONS 预检一直 401,跨域头也加了,为啥浏览器还报跨域?
日期:2026年10月13日 阅读:102
-
同一笔支付回调来了三次,货发了两回,只加唯一索引算防住了吗?
日期:2026年10月11日 阅读:38
-
消息队列堆了几十万条,加了一倍消费者还是没降,是不是分区数卡住了?
日期:2026年10月10日 阅读:81




