分页优化实战:深分页、游标翻页和SEO的那些坑
深分页?别用OFFSET了,那是个无底洞我刚入行那会儿,在个电商公司做后端。订单表几千万,产品非要搞一个“跳转到第500页”的功能——结果你猜怎么着?每次点那个页码,数据库CPU直接飙到90%,DBA提着刀就过来了。后来一查,OFFSET 100000这种写法,MySQL得把前面10万行全扫一遍再丢掉,简直反人类。
深分页的坑,说穿了就是 OFFSET + LIMIT 的机制问题。数据库不能直接跳到第N页,它得顺序数数。数据量越大、页数越深,查询就越慢。这可不是线性增长,是灾难性的。我做过测试,千万级表,OFFSET 1000000的时候,查询时间从毫秒级飙升到几十秒。
https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/793ed3e6-dcd9-4d61-a91b-c29ed5f225ac.jpg
MySQL深分页OFFSET性能下降曲线图
怎么办?游标分页(Keyset Pagination)是解药。别用页码了,改用上一页最后一条数据的ID或时间戳作为锚点,WHERE id > last_id ORDER BY id LIMIT 20。这样数据库直接走索引,快到飞起。但——注意这个但——游标分页不能跳页,只能一页一页翻。产品经理肯定不干,用户也习惯那个小页码。所以后来我们搞了个折中:前100页用OFFSET,100页之后切换到游标,同时隐藏跳页功能,只留上下页按钮。用户体验稍稍牺牲,但数据库稳如老狗。
游标分页很美好,但产品经理不答应
游标分页还有个麻烦:排序条件复杂的时候,比如按多个字段排序,或者字段值可能重复,你就得用复合游标。比如 ORDER BY create_time DESC, id DESC,然后WHERE条件要写成 (create_time 。说实话,写着写着就开始怀疑人生。
而且!有时候需求非得支持“回到第一页”、“跳到最后一页”。游标直接懵逼。这时候你就得结合缓存和预计算。比如把某些热门分类的前100页结果缓存到Redis,或者异步生成静态页。我见过一个神操作:用Elasticsearch的search_after,天然支持深分页,还能做复杂排序,就是运维成本高一些。反正别一条道走到黑。
哦对了,前端那一块也有讲究。无限滚动(Infinite Scroll)是移动端标配,但放到PC端不一定合适。而且一旦用了无限滚动,SEO基本就放弃了——爬虫不会自动往下滚。所以如果是内容型网站,别头脑发热上无限滚动,老老实实分页,或者用“加载更多”按钮,好歹能给爬虫留个入口。
https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/6ae81995-f598-4beb-8630-c84b5cc21026.jpg
网页分页加载更多按钮与无限滚动UX对比
分页的SEO大坑:收录和权重流失
https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/643445d6-ef94-4bc6-a852-30c06b2a40d8.jpg
分页的SEO大坑:收录和权重流失
做SEO的都知道,分页页面如果处理不好,会吃掉你一堆抓取配额,还会稀释权重。早些年Google还支持rel="prev"和rel="next",现在人家明确说了,不咋用了。那我们怎么搞?
我自己的站,分类列表页分页,前三页让搜索引擎索引,从第四页开始加 。这样链接权重还能往后传,但不会让低质分页页进入索引。更重要的是,每个分页页面的title和description要动态生成,加上“ - 第2页”,避免重复。不然Google看几十个页面标题都一样,直接给你归到“重复网页,未选择规范网址”。
还有人把分页页面全部canonical到第一页——这招太粗暴了。分页页面上的商品或文章链接可能本身有排名价值,你一刀切,这些链接可能就得不到足够的内部权重。所以我倾向用View All页面:把所有内容放在一页上,分页页面canonical到这个View All页。但前提是数据量不大,否则加载速度感人。我有个内容站,列表项不超过200,就直接整一个View All,所有分页跳转到这里,SEO效果拔群,页面速度优化后也没问题。
对了,还有个小技巧:分页URL参数别用奇奇怪怪的参数,尽量用路径式,比如 /category/page/2/,清晰明了。Google官方也推荐这种。
缓存是块砖,哪里需要哪里搬
https://obgeo.oss-cn-beijing.aliyuncs.com/pvc-articles/5c4c9d2e-7cef-4d79-8186-288784d81fd2.jpg
缓存是块砖,哪里需要哪里搬
性能优化最后一块拼图通常是缓存。分页查询的结果,如果数据变动不频繁,完全可以缓存起来。比如新闻列表的第一页,访问量巨大,缓存5分钟就能减少99%的数据库查询。但要注意一致性:一旦有新内容发布,你得及时失效第一页缓存,不然用户看到的是旧闻。用Redis的键设计可以这样:list:news:page:1,发布新闻时删除这个键。第二页以后的缓存可以放长一点,因为反正没人看——开玩笑的,但确实深分页命中率低,缓存预热意义不大。
还有一种骚操作:把分页结果静态化。我有个展示型网站,内容几乎不变,直接生成HTML片段扔到CDN,连服务器都不要。这属于极端优化了,但思路值得借鉴——能静态就别动态,能缓存就别实时算。
好了,就说这么多吧。分页优化这事儿,说大不大说小不小,搞不好就是性能瓶颈和SEO灾难。踩过坑才知道疼,希望能帮你少走点弯路。
页:
[1]