网易首页 > 网易号 > 正文 申请入驻

为什么你的分页会漏数据?Offset和游标都有坑

0
分享至

  翻页翻到一半,同一条帖子又冒出来了。再往下滑,昨天明明看到过的那条,怎么找都找不到了。用户不会截图来投诉,测试环境也永远复现不了——因为你的测试库里,没人在你翻页的间隙往表里插数据。

  问题出在那句被复制粘贴进无数代码库的查询上:LIMIT 20 OFFSET 40。它读起来很顺,能过代码评审,能跑通你写的每一个测试。但在任何有人正在写入的表上,它会让一部分用户看到重复的内容,同时悄悄把另一些内容藏起来。

  

  深分页慢这件事,大家都知道。真正少有人注意的是:它在活跃表上本身就是错的。而那个被当成标准答案的修法——游标,也藏着自己在并发下的漏洞,只是博客里的基准测试照不出来。

  OFFSET 是一个位置,而位置会移动

  OFFSET 40 的意思不是"第三页"。它的意思是:把整个查询从头再跑一遍,在当前结果里走过前 40 行,然后把接下来的 20 行给我。页边界是一个数字,而这个数字每次请求都会对着表的当前状态重新算一遍。

  拿一个按时间倒序的信息流走一遍:

  你打开第一页(OFFSET 0),看到的是第 100 条到第 81 条。

  你正在读的时候,两条新帖发布了:101 和 102。

  你点"下一页"(OFFSET 20)。查询现在从 102 开始数,第 1 到 20 位是 102 到 83,第 21 到 40 位是 82 到 63。

  第二页开头是 82 和 81——这两条你刚才已经看过了。

  插入发生在你的位置之前,行就被推向你,于是你看到重复。删除则相反:如果点下一页之前第一页有两条被删掉,所有内容上移两位,原本排在第 21、22 位的两条会滑进你已经离开的第一页,你永远看不到它们。

  Use The Index, Luke 把它总结成一句话:插入新数据时页码会漂移,因为编号永远是从头算的。微软 EF Core 的文档讲 Skip/Take 时说的是同一件事:一旦发生并发更新,分页可能跳过某些条目,或者把它们显示两次。Slack 在 API 规模增长时撞上的正是这个,他们那篇从 offset 迁移的工程文章里写道,当条目被频繁添加时,页窗口会变得不可靠,可能跳过或返回重复结果。

  重复很烦,跳过才危险,因为它看起来什么都没坏。用户刷信息流不会察觉。一个每晚翻页把订单推进数仓的定时任务同样不会察觉——这就是为什么你最后会得到一份每天差几行的对账报告,而没人说得清差在哪。

  你忘写的 ORDER BY 是另一个 bug

  在谈并发之前,还有同一个问题的安静版本。Postgres 文档在这点上措辞罕见地直白:使用 LIMIT 时,重要的是用一个能把结果约束成唯一顺序的 ORDER BY 子句,否则你拿到的是查询行的一个不可预测的子集。

  紧接着还有一句:查询规划器在生成计划时会把 LIMIT 考虑进去,所以你给不同的 LIMIT 和 OFFSET,很可能得到不同的计划,从而产生不同的行顺序。改一下 offset,可能换一个计划,可能换一个顺序。文档补充说,这不是 bug——SQL 从来没有承诺过你没要求的顺序。

  所以光写 ORDER BY created_at DESC 不够。只要两条帖子共享同一个时间戳(批量导入、种子数据、任何在同一事务里用 now() 写入的东西),它们的相对顺序就交给规划器决定,而一个正好落在它们之间的页边界,可能给你其中一条、两条、或者一条都不给。EF Core 文档还补了一个经常被搞错的细节:关系型数据库默认不施加任何排序,主键上也不施加。

  修法无聊但必须做:排序的末尾永远加一个唯一列。

  ORDER BY created_at DESC, id DESC

  这个决胜列对 offset 和游标都重要。对游标来说它根本不是可选项。

  深 offset 为什么慢,机制值得用一句话说清。Postgres 文档的说法是:被 OFFSET 子句跳过的行仍然要在服务器内部被计算出来,因此一个很大的 OFFSET 可能效率低下。

  用 B 树绕不开这一点。你可能会想,索引直接跳到"第 40000 行"不就行了——它做不到。CedarDB 团队指出,B 树的每个分支并不包含固定数量的元组,所以没有东西可以用来计算这个跳跃。数据库从索引起点开始走,把 offset 之前的每一行都丢掉。Slack 的说法是:数据库仍然要从磁盘读取最多 offset + count 行。第一页读 20 行,第 2000 页为了返回 20 行要读 40000 行。

  伤害有多大取决于你的数据、索引,以及行是否被缓存,所以这里不给一个编造的毫秒数。Markus Winand 在 Use The Index, Luke 上的基准图表显示,offset 和 seek 方法的差距大约从第 20 页开始变得清晰可见,之后曲线只会更陡。

  Keyset:记住那一行,而不是那个数字

  两个问题的修法是同一个思路。不要告诉数据库跳过多少行,告诉它你停在哪里。这就是 keyset 分页,也叫 seek 方法。

  第一页照常查,按 created_at 和 id 倒序取 20 条。第二页把第一页最后一行的 (created_at, id) 传进去,用 WHERE (created_at, id) < ($1, $2) 过滤,再取 20 条。

  这个行值比较是字典序的:先比 created_at,相等才比 id。有了 (created_at, id) 上的索引,Postgres 可以直接定位到那个点,不需要从头走过被跳过的行。

  代价是游标不能跳页,只能一页一页往下。对信息流和导出任务来说,这通常不是问题;对需要"跳到第 37 页"的后台表格来说,它是个真实的限制。但至少,它不会在你翻页的时候,把别人刚写进去的数据变成你眼前的重复和消失。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
广东男篮为什么打不过山东队?广东主帅一席话,直接戳中要害

广东男篮为什么打不过山东队?广东主帅一席话,直接戳中要害

阿嚼影视评论
2026-10-10 06:35:27
中共中央、国务院:加快突破关键核心技术

中共中央、国务院:加快突破关键核心技术

每日经济新闻
2026-10-09 18:14:06
日本提折中方案,中方当场拒绝,毛宁斩钉截铁:凭啥考虑高市面子

日本提折中方案,中方当场拒绝,毛宁斩钉截铁:凭啥考虑高市面子

棠棣分享
2026-10-09 11:56:46
现在才发现小布什是口碑最好的总统。特朗普从克林顿骂到奥巴马、从拜登骂到佩洛西,唯独从来不提小布什!不知道是为什么?

现在才发现小布什是口碑最好的总统。特朗普从克林顿骂到奥巴马、从拜登骂到佩洛西,唯独从来不提小布什!不知道是为什么?

扶苏聊历史
2026-10-09 17:02:37
吴易昺炮轰世界第2:赢得不纯粹!用抱怨灯光+摆弄网带来干扰比赛

吴易昺炮轰世界第2:赢得不纯粹!用抱怨灯光+摆弄网带来干扰比赛

我爱英超
2026-10-09 17:45:44
19年穆沙拉夫被判死刑,巴法庭还要求悬尸三天,军方公开严厉斥责

19年穆沙拉夫被判死刑,巴法庭还要求悬尸三天,军方公开严厉斥责

风雨与阳光
2026-10-09 21:08:25
iPhone Duo新功能,可能让刷手机更难停下来

iPhone Duo新功能,可能让刷手机更难停下来

像素与芯片
2026-10-10 03:44:16
巴萨天赐良机!弗里克坐等捡漏!1.2 亿巨星铁心加盟诺坎普

巴萨天赐良机!弗里克坐等捡漏!1.2 亿巨星铁心加盟诺坎普

澜归序
2026-10-10 08:54:16
压过 1.05 亿赖斯!阿尔特塔瞄准金球级巨星!阿森纳史诗引援来了

压过 1.05 亿赖斯!阿尔特塔瞄准金球级巨星!阿森纳史诗引援来了

澜归序
2026-10-10 09:28:11
28%到8% 最新民调大反转!赵少康成沈伯洋功臣 郑丽文实在太憋屈

28%到8% 最新民调大反转!赵少康成沈伯洋功臣 郑丽文实在太憋屈

放开他让wo来
2026-10-09 13:05:34
郑钦文开心比出“24”手势庆生!仅用46天王者归来:排名飙升86位

郑钦文开心比出“24”手势庆生!仅用46天王者归来:排名飙升86位

我爱英超
2026-10-09 17:43:54
李冰冰戛纳说狠话,亲姐妹冷战三个月,来生不要和妹妹做同事。

李冰冰戛纳说狠话,亲姐妹冷战三个月,来生不要和妹妹做同事。

东方不败然多多
2026-10-09 15:29:33
韩媒:金玟哉等96一代球员向韩国足协反馈孙兴慜的领导力问题

韩媒:金玟哉等96一代球员向韩国足协反馈孙兴慜的领导力问题

懂球帝
2026-10-09 11:19:15
阿根廷刚独立时,三分之一人口是黑人,今天却几乎看不见了,为什么

阿根廷刚独立时,三分之一人口是黑人,今天却几乎看不见了,为什么

孤云朗境
2026-10-10 02:30:22
外资撤不走,中国拦不住,如今的中国广东,制造早已不是代工

外资撤不走,中国拦不住,如今的中国广东,制造早已不是代工

风流女汉
2026-10-10 01:01:09
川普是人不是神,他只是在拼力做自己认为应该做的事

川普是人不是神,他只是在拼力做自己认为应该做的事

壹家言
2026-10-08 10:09:11
“再降薪就没人踢了”,徐亮暴怒发声的原因出来了,范志毅说对了

“再降薪就没人踢了”,徐亮暴怒发声的原因出来了,范志毅说对了

娱说瑜悦
2026-06-17 13:53:07
李玮锋被解约!媒体人热议:语气带着恨,欠薪数月+股东纠纷

李玮锋被解约!媒体人热议:语气带着恨,欠薪数月+股东纠纷

奥拜尔
2026-10-09 12:52:38
中央5台直播乒乓球:10月10日CCTV5、CCTV5+节目单!中日争冠

中央5台直播乒乓球:10月10日CCTV5、CCTV5+节目单!中日争冠

安逸安逸
2026-10-10 02:24:17
河南省政府新任免一批干部

河南省政府新任免一批干部

黄河新闻网吕梁
2026-10-09 17:59:47
2026-10-10 09:52:49
薛定谔的BUG
薛定谔的BUG
有态度网友ytd
213文章数 104关注度
往期回顾 全部

科技要闻

上世纪成熟的踏板,为何今天还会断裂?

头条要闻

男子称吃出胶圈索赔1000元 商场发现异样:一天吃4顿

头条要闻

男子称吃出胶圈索赔1000元 商场发现异样:一天吃4顿

体育要闻

与C罗硬碰硬,一个72岁老人的倔强

娱乐要闻

胡歌现身游本昌遗体告别仪式

财经要闻

蹭尊界流量?岚图汽车在“玩火”

汽车要闻

2027款深蓝L06及追风版上市 限时权益价11.49万元起

态度原创

游戏
亲子
教育
旅游
公开课

暗黑战棋 重大更新!全新可控角色+终极BOSS加入

亲子要闻

山西一孕妇在医院开保胎药,取药时却拿到可导致流产的缩宫素,医院回应:工作人员给错药,已被停职检查

教育要闻

“Petty”不是“小”!这个被科比表情包带火的英语俚语,戳中了14亿人“记仇”的DNA

旅游要闻

2026年度“徒步·寻迹齐长城”国家文化公园主题活动举办

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版