请教后端分页的常用方法

2023-04-24 20:14:41 +08:00
 873792861
如题,请教下后端分页一般是怎么搞的呢?我百度了不少网页都是先查询 count ,然后再使用 limit offset 这样子的思路。但这样子,我有个疑惑,那岂不是每次点击下一页或者上一页,请求数据的时候,我都查询了一遍 count(*),这样子才能拿到 total 的值。有更好的解决办法吗?
1662 次点击
所在节点    编程
10 条回复
sadfQED2
2023-04-24 20:17:23 +08:00
mysql 的话每次都得手动 count 一下,其他引擎不一定。比如 es 每次都会自动返回 total
hhjswf
2023-04-24 20:19:58 +08:00
无解。前端做一下缓存吧,查询条件变化就清掉
fox0001
2023-04-24 20:20:41 +08:00
不 count 总数量的话,可以把数据按固定顺序排列,每次加载上一页最后一条数据之后的 N 条数据。
lovelylain
2023-04-24 20:35:08 +08:00
如果只允许连续一页页翻,不需要做成输入页码直达任意页面的话,类似朋友圈这种,可以带上次结果最后一条的 id 作为过滤条件
opengps
2023-04-24 20:42:51 +08:00
如果你数据量不变(不新增,不修改,不带过滤)那么你可以全局变量存下 count 值来省掉这个查询
wunonglin
2023-04-24 20:45:13 +08:00
@lovelylain #4 在常规业务中,列表还是需要 total 的,无限刷新的不适合这种场景。而且在通常的业务中,CURD 需要实时性,所以缓存其实不是“那么地”必要。
873792861
2023-04-24 20:54:20 +08:00
@opengps 一般都是变化的呢
XCFOX
2023-04-24 22:06:48 +08:00
如果数据规模不大,查询结果的行数在几千行以内,通常不需要特别优化,直接 count(1) 不会有大的性能问题。

如果数据规模较大,查询结果行数在几十万行规模以上级别,这时候翻页都是麻烦事儿。一般会在数据库内另外记一个值来存手动 count ,每次新增行 count + 1 ,每次删除行 count - 1 ,通过事务来确保与实际行数一致。
比如知乎的粉丝列表页面: https://www.zhihu.com/people/gong-qing-tuan-zhong-yang-67/followers?page=2333
翻页翻到后面直接不展示数据了,因为此时数据库需要 skip 上万行才能查询到结果,开销太大了。

另外一个很实用的办法是把分页换成加载 [加载更多],这样就不用 count 了,用户也更难 skip 上万行。
huijiewei
2023-04-24 22:20:51 +08:00
分页 count 才是小问题,mysql 数据量大了以后 limit offset 才是大问题,如果你连 limit offset 的问题都遇不到,那考虑 count 的问题真的是庸人自扰
waitingChou
2023-04-25 11:59:09 +08:00
你细想一下,如果你想精确展示 总页数,这个 count 值是肯定需要的对吧? 查询是避免不了的。

如果你觉得每次查询有点浪费,那缓存的作用就是减少 DB 查询压力的,所以上缓存就好了,至于前端缓存还是后端缓存看你的业务;
缓存更新机制则看数据实时性要求,要求比较低可以设置个几分钟自动过期都行。

但如其他楼提到的,相比于 count ,翻页到很后面的时候 limit offset 的问题一般更大一点,DB 要抛掉非常多的数据才能取到当前页。

所以现在蛮多地方都直接不显示总页数,而是”前一页 /后一页“的方式,因为很少有人真的翻到非常后面的页数,不必要花大力气支持这个伪需求。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/935147

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX