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

分页写错会漏数据?游标也有自己的坑

0
分享至

  翻页翻到一半,同一条帖子又冒出来一次;再往下翻,有几条却像从没存在过。这不是前端渲染的锅,问题出在那句被复制粘贴进无数代码库的 SQL 上。

  它读起来很顺,代码评审能过,测试也全绿——因为测试里没人会在你翻到第二页和第三页之间往表里插数据。可一旦表是活的,有人正在写,它就会让一部分用户看到重复内容,同时悄悄把另一些内容藏起来。

  

  第二种失败更值得说。大家都知道 OFFSET 翻到深页会变慢,但很少有人注意到它在活跃表上本身就是错的;更少人知道那个流行的修法——游标——也有自己的并发漏洞,而且这个漏洞在博客的基准测试里根本不会露头。

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

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

  拿一个按时间倒序的 feed 走一遍:

  你加载第一页(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 迁移的工程文章写道,在频繁新增条目的场景下,“页面窗口变得不可靠,可能跳过或返回重复结果”。

  重复很烦,跳过才危险,因为它看起来什么都没坏。用户刷 feed 不会察觉;一个每晚分页扫订单、往仓库推数据的任务也不会察觉——于是你每天的对账报告都差那么几行,没人说得清为什么。

  你忘写的 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 DESC, id DESC 排序取 20 条。第二页把第一页最后一行的 (created_at, id) 传进去,用 WHERE (created_at, id) < ($1, $2) 过滤。这是一个行值比较,按字典序:先比 created_at,相等才比 id。有了 (created_at, id) 上的索引,Postgres 能直接定位到那个点。

  但游标不是免费的午餐。它同样依赖那个唯一决胜列,否则边界落在相同时间戳之间时,你依然会漏行或重复。它把“位置会移动”换成了“记住具体那一行”,代价是不能再直接跳到第 N 页,只能一页页往前翻。

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

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万元起

态度原创

本地
家居
时尚
数码
游戏

本地新闻

转型再出发 奋勇打头阵

家居要闻

2026建博会(广州) 公装联探展交流活动

时尚早知道!2027春夏十大流行趋势

数码要闻

冲击4GHz!爆料称AMD RDNA 5桌面显卡频率大涨:远超RX 9070 XT

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

无障碍浏览 进入关怀版