V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
873792861
V2EX  ›  编程

请教后端分页的常用方法

  •  
  •   873792861 · 2023-04-24 20:14:41 +08:00 · 1950 次点击
    这是一个创建于 590 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题,请教下后端分页一般是怎么搞的呢?我百度了不少网页都是先查询 count ,然后再使用 limit offset 这样子的思路。但这样子,我有个疑惑,那岂不是每次点击下一页或者上一页,请求数据的时候,我都查询了一遍 count(*),这样子才能拿到 total 的值。有更好的解决办法吗?
    10 条回复    2023-04-25 11:59:09 +08:00
    sadfQED2
        1
    sadfQED2  
       2023-04-24 20:17:23 +08:00 via Android
    mysql 的话每次都得手动 count 一下,其他引擎不一定。比如 es 每次都会自动返回 total
    hhjswf
        2
    hhjswf  
       2023-04-24 20:19:58 +08:00 via Android
    无解。前端做一下缓存吧,查询条件变化就清掉
    fox0001
        3
    fox0001  
       2023-04-24 20:20:41 +08:00 via Android
    不 count 总数量的话,可以把数据按固定顺序排列,每次加载上一页最后一条数据之后的 N 条数据。
    lovelylain
        4
    lovelylain  
       2023-04-24 20:35:08 +08:00 via Android
    如果只允许连续一页页翻,不需要做成输入页码直达任意页面的话,类似朋友圈这种,可以带上次结果最后一条的 id 作为过滤条件
    opengps
        5
    opengps  
       2023-04-24 20:42:51 +08:00
    如果你数据量不变(不新增,不修改,不带过滤)那么你可以全局变量存下 count 值来省掉这个查询
    wunonglin
        6
    wunonglin  
       2023-04-24 20:45:13 +08:00
    @lovelylain #4 在常规业务中,列表还是需要 total 的,无限刷新的不适合这种场景。而且在通常的业务中,CURD 需要实时性,所以缓存其实不是“那么地”必要。
    873792861
        7
    873792861  
    OP
       2023-04-24 20:54:20 +08:00
    @opengps 一般都是变化的呢
    XCFOX
        8
    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
        9
    huijiewei  
       2023-04-24 22:20:51 +08:00
    分页 count 才是小问题,mysql 数据量大了以后 limit offset 才是大问题,如果你连 limit offset 的问题都遇不到,那考虑 count 的问题真的是庸人自扰
    waitingChou
        10
    waitingChou  
       2023-04-25 11:59:09 +08:00   ❤️ 1
    你细想一下,如果你想精确展示 总页数,这个 count 值是肯定需要的对吧? 查询是避免不了的。

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

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

    所以现在蛮多地方都直接不显示总页数,而是”前一页 /后一页“的方式,因为很少有人真的翻到非常后面的页数,不必要花大力气支持这个伪需求。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5769 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 03:19 · PVG 11:19 · LAX 19:19 · JFK 22:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.