传统分页的话,一般只考虑传页数和每页数据条数这两个参数给后端,为了方便后面描述,我们给这个传参方式起个名字叫 传统分页 。这种传参方式对于静态数据(数据不会变动)的分页是没问题的,因为每条数据的顺序、数据的总量,都是不变的。
如果出现数据顺序变动或者数据总量变动的分页需求时,单纯的传page和limit已经不能解决了。
不同的需求需要显示的列表也不一样。关于列表分页我认为主要关系到两个方面, 总量 (列表头插入了新数据) 和 排列顺序 。 传统分页 在 总量不变,排列顺序不变 的列表下是没有任何问题的,但只要这两个要素其中一个是变化的, 传统分页 方式就会出现BUG(具体案例后面会讲到)。关于上面提到两个要素对应的需求举例:
现在有一个积分排行榜
假定每页显示3条数据,在某一时刻拿第一页数据时,得到 A、B、C三条数据。就在此时,用户D突然增加了100积分,最新的排行榜情况变成了
传统分页 的情况下,获取第二页数据时,即从当前排行榜第四条数据开始获取,得到 C、E,用户看到的数据就变成 A、B、C、C、E。这里C出现了2次,而且D消失了。这就是传统分页用在 数据排列顺序会改变的列表 时会出现的问题,因为列表顺序改变导致出现重复数据和丢失数据。
这种 总量不变,排列顺序改变 的分页问题我能想到的暂时有两种方案解决:一次性取出、排行榜快照、通过变动记录表拿数据。
这里说的一次性取出是针对类似“top100”这种取有限条数的需求。在比较简单的列表数据结构下一次性取出100条数据对服务器性能来说问题不大,但是在复杂数据结构下(涉及关联多个表、数据格式化、数据处理等)一次性处理100或更多的数据肯定是糟糕的做法。
排行榜主要的分页问题是 影响排名的字段的值在不断变化导致列表顺序不断改变 ,我们现在可以一次性取出整个列表但是又担心复杂的数据结构导致服务器性能问题。那如果我们把整个功能拆分一下,用异步的思想来做这个功能设计如何呢。
我们分两个接口来做这个功能:获取排行榜列表和获取用户排行榜数据。
获取排行榜列表接口 一次性取整个排名列表的用户ID和排名相关的字段数据,这样就保证了整个列表的排序是不变的同时,又不增大服务器性能。
获取用户排行榜数据接口 负责取排行榜要显示的用户的其他数据,这个接口接受多个用户ID的作为参数。这个接口做了类似分页的功能,前端每次从排行榜中按分页的方式按顺序取部分用户ID,然后通过这个接口获取具体数据显示给用户。
下面以例子的方式来做具体说明:
这是一个 积分排行 top100
这里的排行条件是 积分 ,那我们的 获取排行榜列表接口 只需要取“用户ID”和“积分”即可,剩下的 “昵称”、“胜率”等数据通过 获取用户排行榜数据接口 获取。
前端先请求 列表接口,获取到一下数据:
然后根据这个列表数据,先取前10条的用户ID:5、12、60、2、77… 去请求 获取用户排行榜数据接口,把获得的用户数据填充到排行榜中。当用户下滑加载更多数据时再去列表取在11-20的用户ID重复上面的 *** 作。
如果是 top100 的需求,这个方案是比较 推荐 的,因为没有性能和储存空间上的额外消耗。
因为考虑到主要问题出在排列顺序是变化的,而且通过其他APP也有看到过按时刷新的排行榜,所以想到了用快照的方式来解决。
可以通过写一个定时脚本,每5分钟生成一次排行榜的快照信息并存下来。接口请求时直接从快照中取数据,这一定程度上解决了列表排序一直在变化问题。这里之所以说只解决了一定程度,是因为在每次刷新快照数据的时候,可能有用户刚好卡在这个时间点之间去请求(刷新快照前用户请求了第一页数据,刷新快照后用户请求第二页,这就出现 传统分页 同样的问题了)。
可以通过在快照中加上 版本号 来解决问题。例如在生成快照的时候以当前时间戳作为版本号跟快照数据一起保存,同时需要系统保存多份快照数据以便用户获取旧快照数据。请求接口时默认拿最新版本的快照,如果接口传入了版本号就拿对应版本号的快照数据。
每个完备的系统都会有数据变动的记录表,用于追踪数据变动和 *** 作明细。记录变记录着数据每次变动前后的变化和变动时间,这一特性为使得数据的每次变动都有迹可循,我们就是利用这一点来做排行榜的分页。
我们分页出问题的地方就是因为数据在不断变化导致排序不停改变。上面说到每次数据变动都会有记录,那我们只需要根据某一时刻之前用户的数据来做排名,是不是就解决数据不断变动这个问题。文字表达可能不太直观,看下面的数据演示应该能比较好理解。
假定用户 A、B、C 初始默认都是100积分
表: score_log
假定在03分的时候请求了数据,通过下面的SQL语句就可以拿到03分之前的数据排行。
得到第一页数据:
第二页数据:
关于这种方式的请求,前端需要记录发起第一次请求时的时间,以后每页的请求都带着这个时间。
评论列表一般按照倒叙排列,而且顺序不变。因为是倒叙排列,所以最新的用户评论会放在最顶部,这就会导致问题了。我们还是用实际例子来说。
假定每页拿3条数据,此时请求第一页,得到ID分别5、4、3的评论。在请求第二页之前,突然又来了一条留言,此时列表变成:
用 传统分页 方式,此时获取第二页会得到ID 3、2、1,这里ID 3 就重复取出来了。
这个问题的解决方案相比排行榜列表分页问题简单而且易懂。评论ID是一个自增的int字段,新的评论ID总是比旧评论ID要大,利用这一点我们可以很好的解决问题。
接口传参:
limit 就不用作解释,说一下lastid。当获取第一页数据时,因为没有上一页所以 lastid 传空或者不传,此时服务器取最新的数据即可。获取第二页数据时,lastid 传第一页最后一条数据的ID,此时服务器取 ID < lastid 的数据,这就保证最新的评论不会影响到当前用户的分页。
这里做一个扩展,我们有时候看到有的页面在刷新的时候,会提示有多少条新的未查看评论(即列表头新的数据),这个功能的实现原理跟我们上面分页的原理差不多。在获取第一页数据时,把第一页的第一条数据ID保存下来,后面请求每一页时都把第一条ID( firstid )带上,服务器每次查 ID > firstid 的数据条数,如果大于0即表示有新的评论。
首先说一下,下面提供的方法我自己也不满意(如果有什么想法欢迎大家留言交流)。参考了微博的评论排序也存在上面说到的分页bug,感觉要完美解决这个需求的分页问题花费的代价(实现时间、服务器性能、存储空间等)大于功能本身,所以建议读者选择比较折中的方式来处理(与产品或上级沟通实现的难度)。
这个需求相比评论列表,多了点赞的功能,列表按点赞数量倒叙排列。先说一下不严谨情况下这个分页的实现方式:
这种方式会有两个问题:
我们可以沿用上面讲到的两个需求的解决方案。在解决列表排序问题上,我们可以沿用排行榜的 通过变动记录表拿数据 方式,增加一个表去记录评论的点赞变动记录(用空间换效率)。
表结构:
分页用到的查询语句:
select PUserPoliceId,
rownum '排名'
from(
select PUserPoliceId, c
from (select PUserPoliceId, count(1) c
from table
where pCorrect = 1
group by PUserPoliceId)
order by c desc)
where PUserPoliceId = 110;
>
排名前五的App分别是微信、淘宝、支付宝、抖音和高德地图。
QuestMobile发布“App用户规模亿级玩家”榜单,微信、手机淘宝、高德地图、WiFi万能钥匙等成为国内用户数量最多的Top20应用。榜单信息显示,这些App的月度活跃用户数量均在34亿人以上,拥有广泛的用户基础。
根据榜单,排名前五的App分别是微信、淘宝、支付宝、抖音和高德地图,其中排名第一的微信月活跃用户突破10亿。拼多多、QQ、百度、搜狗输入法、百度输入法、微博、百度地图、京东、爱奇艺、QQ浏览器、腾讯视频、快手、WiFi万能钥匙、美团和今日头条分别位列第六到第二十名,月度活跃用户在63亿到34亿之间。
开发app的注意事项
app开发前期规划要做好相关调研,无论是app所在行业和相关行业的市场调研,还是该app可能面向的客户群的用户调研,都是app开发前期规划必须考虑到的。市场调研主要是了解市场的整体需求,注重市场定位和品牌价值。另一方面,用户研究的重点是用户如何与您的APP交互,主要收集用户对APP使用的反馈,并整理和提出修改建议。
app开发前期规划要做好相关研究,我们需要做好定量研究的同时做好定性研究。在定量研究中,数据通常是通过问卷调查或网络分析收集的,而不是直接从受访者那里收集。定量分析可以帮助你理解发生了什么,或者在多大程度上。定性分析数据直接从参与者那里收集,通常以访谈或可用性测试的形式。
以上就是关于分页功能设计(解决数据重复问题)全部的内容,包括:分页功能设计(解决数据重复问题)、SQL语句先根据ID统计条数再计算排名 查询 pCorrect=1时 PUserPoliceId=110 这个用户的排名。、如何查看用户积分排名,我想找优秀的ID等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)