从产品设计上用limit优化count

Categories:

当列表内容很多的时候,分批加载是不得不考虑的设计。
在PC端上,往往会采用分页的设计。但在移动端,有时也会考虑下拉滚动时加载更多。
加载更多

在程序开发上,各种分页插件几乎都很完善了。
一般都会先执行一个count语句,如果count为0直接结束。
如果count>0再生成一个分页语句。
以java的mybatis-plus为例,甚至提供了count的优化。
例如当你提供一个原始的sql

select 一堆字段 from  where 一堆条件 order by 排序

以前我们自己写的话都是直接外层包一个count,变成

select count(*) from (select 一堆字段 from  where 一堆条件 order by 排序)

现在的sql parser等基础设施也比较完善,工具库一般都会帮我们优化下sql了, 例如去除order by,去除select的一堆字段,变成

select count(*) from  where 一堆条件

前段时间,项目团队里的小伙伴在做性能测试,造了一堆数据。 虽然分页本身确实只查询10条,但是count(*)本身没法优化,只能全部查出来再一条条累加计数。
正在技术层面焦头烂额的时候,我去看了看界面。
发现界面上根本不关注准确的总数,当大于999的时候数量直接显示999+。
加载更多采用的也是滚动下拉,不存在直接跳去某页的操作。

于是我们从业务角度出发对技术实现做了调整。

接口拆分方案

  1. 接口拆分。将一个接口同时返回total和数据,拆分成一个接口只返回total,另一个接口只返回数据。
    // 原始接口
     {
         "total": 3123421,
         "page": 1,  //当前第几页
         "size": 10, //每页多少条
         "data": [{},{},{},{},{},{},{},{},{},{}] //<=10条数据
     }
    // 拆分后的count接口
    {
         "total" : 1000 //>=1000时返回1000
    }
    //拆分后的数据接口
    {
         "page": 1,
         "size": 10,
         "data": [{},{},{},{},{},{},{},{},{},{}] //<=10条数据
    }
    
  2. 在count前加limit,实现数量<1000时就返回真实数量,>=1000时就返回1000。
    select count(*) from (select 1 from  where 一堆条件 limit 1000)
    
  3. 前端首先调用一次count接口,用于显示预估总数。若为0,可直接省掉数据接口调用。 调用数据接口,若是data元素<size,则可断定当前已是最后一页;否则则可继续加载。

接口不拆分方案

若是不想做接口拆分,可以把分页字段page、size换成hasMore。
如果不想前端改,也可以做如下改动

// 原始接口
{
    "total": 1000, //小于1000如实显示,大于1000时默认返回1000
    "page": 1,  //当前第几页
    "size": 10, //每页多少条
    "data": [{},{},{},{},{},{},{},{},{},{}] //<=10条数据
}

假设分页已经到了第101页,若返回total=1000则违反常识。

{
    "total": 1000, //违反常识
    "page": 101,  
    "size": 10, 
    "data": [{},{},{},{},{},{},{},{},{},{}] //<=10条数据
}

因此可以增加调整规则,若本次data数量<size,则说明肯定没有更多数据,则

total = (page - 1) * size + data.length
{
    "total": 1002,
    "page": 101,  
    "size": 10, 
    "data": [{},{}] //<10条数据
}

若本地data数量==size,则可能还有更多数据,则

total = page * size + 1
{
    "total": 1011, 
    "page": 101,  
    "size": 10, 
    "data": [{},{},{},{},{},{},{},{},{},{}] //<=10条数据
}

产品设计背后的思考

真的需要准确的总数吗? 其实我们真的需要准确的总数吗?
不可否认有些时候总数还是有意义的。
但对大多数需要处理的事务性工作来说,你反正是要一条一条处理的,显示999+和321343对你来说真的有区别吗?

如果你觉得本文对你有帮助或不错,可略表心意,请我喝一杯冰可乐。

Comments