TONY 发表于 2026-07-20 19:07:12

分页优化,这坑我踩过,你千万别再掉进去

做站长这些年,我养成了一个习惯——看一个网站的技术底子,先翻它几页搜索结果。一翻一个准。页码越大,加载越慢,甚至直接502,那这网站八成没做过分页优化。

说实话,分页这东西,太基础了。基础到很多开发者压根没把它当回事。不就 limit offset 吗?能跑就行。但现实是,它能跑着跑着就趴窝。而且趴得悄无声息——直到有一天,DBA 举着慢查询日志冲到你工位前。你一脸无辜:数据量又不大啊?

呵呵。分页的坑,就是温水煮青蛙。今天咱就扒开这层皮,聊透它。


你以为的简单翻页,数据库快哭了


先说个真事儿。前年帮一个电商网站做诊断,商品列表翻到第200页就要十几秒。代码明晃晃写着 select * from products limit 40000, 20。你知道数据库在这十几秒里干啥了吗?它吭哧吭哧扫描了整整四万行,然后扔掉前四万行,只取最后20行。像极了翻书时一页页数过去,到第200页才撕下来那20条记录。

MySQL 的 limit offset 就是这样:偏移量越大,性能呈线性下降。原因?数据库根本没办法跳页,它只能顺序扫。即使你有索引,它也未必能用上(覆盖索引除外)。你看到的是一个简单的 SQL,背后却是磁盘 IO 的疯狂咆哮。服务器 CPU 炸了,内存吃紧,查询缓存被冲得七零八落。然后整个站都慢了。


https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/f5346810-830c-400e-963e-cf60ae0c2543.jpg

数据库LIMIT偏移量性能下降曲线图


那怎么办?优化思路其实不复杂——别让数据库做无谓的丢弃。常用的招数有几个:覆盖索引 + 延迟关联。先用索引快速定位到起始位置的 id,再用这些 id 去取完整数据。比如:select * from products inner join (select id from products order by id limit 40000, 20) as tmp using(id)。这样内部查询只扫索引,快得多。但延迟关联写起来啰嗦,而且偏移量极大时仍然需要从头扫描索引,只能说缓解。

还有种更彻底的办法——游标分页。


游标分页:快得像瞬移,但别用错了地方


游标分页,我们内部叫它 “基于指针的翻页”。思路直接:用上一页最后一条记录的某个值作为起始点,加上 where 条件,limit 就不需要 offset 了。比如上一页最后一条 id 是 5000,下一页变成 select * from products where id > 5000 order by id limit 20。无论翻到第几页,数据库都能通过索引直接定位,扫描行数恒定。


https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/359aa4e1-574a-4611-b560-e42b23765c84.jpg

游标分页数据库查询逻辑示意图


我用它解决过不少慢查询。但注意,它有个致命弱点——不能跳页。你只能上一页下一页地走,没办法直接点“第10页”。因为游标依赖连续的序列,中间断档就会丢数据。所以它适合什么场景?瀑布流、信息流、API 增量拉取。那种需要显示总页数、可以任意跳转的分页组件,硬上就是给自己找不痛快。

另外,游标列必须 排序唯一且递增。时间戳?别,高并发下毫秒级重复,数据会乱。主键递增 id 最稳。联合游标也行,比如 where (created_at, id) > ('2024-01-01', 5000)。但架构复杂了,自己掂量。

还有一个反直觉的点:游标分页有时反而会拖慢索引查找?对,如果你碰上一个巨大的非聚簇索引,回表次数多,还不如覆盖索引 + 延迟关联。所以,没有银弹。得看你数据分布和业务需求。我见过一个团队,给千万级用户表硬上游标,结果翻页是快了,列表页一点击用户详情,关联查询一堆,整个接口又垮了。分页优化从来不是单点的事。


SEO角度的分页黑洞:蜘蛛爬不到,流量就跑了


做 SEO 的,最怕听到开发说:“这简单,我把分页参数改成 ajax 加载。”然后你去看源代码,列表全空,内容全靠 js 渲染。Google 虽然能执行 js,但延迟和资源开销摆在那,大量分页翻到天荒地老,蜘蛛早没耐心了。结果?几百个长尾列表页,只收录了前两页。流量损失算谁头上?

分页 SEO 的核心,一句话:让搜索引擎明白,这一连串页面是同一个东西的不同切块。手法就那些:

1. rel="next" 和 rel="prev" 标签。在里加,指明前后页关系。老套但有效,Google 认。注意别写错 URL,带完整路径。

2. Canonical 标签。有人喜欢把所有分页页面的 canonical 指向第一页,这招有争议。因为 canonical 意味着“这页的权威版本是那个”,如果后页内容差异大,会被忽略。我更倾向于让每页自指,提升独立性。

3. 参数规范化。分页参数用 ?page=2,别用奇奇怪怪的 session id 或哈希。Google Search Console 里做好参数处理,告诉爬虫“page”参数不影响内容。

还有一种致命操作:每个分页页面的 title 和 description 一模一样。大哥,这跟告诉搜索引擎“这些页面高度重复”有什么区别?至少搞个 “第X页 - 商品列表” 吧。细节见真章。


https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/bc4f5844-a323-4457-a064-5a26006b6bcf.jpg

搜索引擎爬虫抓取分页页面示意图


还有无限滚动——那对 SEO 简直是毒药。你以为用户体验爽了,但蜘蛛连第2屏都到不了。如果非得用,必须配合 可索引的分页版本,用或者服务端渲染的降级方案。我吃过亏,一个资讯站全改成无限加载,结果自然流量三个月掉了40%。血泪教训。

说到这,你可能会问:那到底哪种分页策略最好?前端交互、后端性能、SEO,好像总打架。是,平衡很难。我的经验是:看场景下菜碟。后台管理系统,用 offset,做好索引覆盖;面向用户的产品列表,游标 + 虚拟滚动;内容站点,老老实实传统分页 + SEO 标签。别想着一个方案通吃。

分页这东西,真的是小功能,大文章。下次别人跟我说“不就是个翻页嘛”,我就把这个分享给他。——嗯,希望他顶住。

LoveYaLots 发表于 2026-07-20 19:08:50

希望楼主常来发帖,持续输出优质内容,我们都会一直支持你。

wylren2 发表于 2026-07-20 19:55:26

说得很有道理,很多观点都说到点子上了,希望以后能多看到这类帖子。

3255967839 发表于 2026-07-21 15:24:39

看了这么多帖子,还是觉得你这篇最实在,条理清晰又容易理解。
页: [1]
查看完整版本: 分页优化,这坑我踩过,你千万别再掉进去