需求
从贴吧列表页
点进视频详情可以上下滑动刷视频
要求每次进入同一个视频详情上下滑动的视频显示的尽量不重复
分析
这个需求的难点是从详情进来后端给的视频列表要不一样并尽量减少重复
方案:
- 如果根据id 排序默认随机一个id 然后>id 数分页返回,存在会出现大量连续重复的数据
- 根据order by rand() 返回,重复出现的概率符合需求但是贴吧数据量比较大,用rand()返回效率堪忧
当用于一个大表时,这可能会减慢使用ORDER BY RAND()函数的执行过程。这是因为MySQL需要对整个表进行排序以找出随机值,这个过程很耗时
我们今天要讲的是除了上面的两种方案的第三种,即MD5(主键id) 生成唯一32位字符的字段,当从详情页请求列表的时候,,通过mysql的substr 函数随机从32位数据中截取一部分排序,下一页的时候仍然根据截取的参数返回下一页数据。当重新进入这个详情的时候重新随机生成截取的位数
实现
SELECT
`posts`.`post_id`,
MD5( `posts_id` ) AS `uid`,
`posts`.`user_id`,
`posts`.`post_content`,
`posts`.`created_at`
FROM
(
SELECT
`post_id`,
`user_id`,
`post_content`,
`created_at`
FROM
`posts`
WHERE
( `posts`.`deleted_at` = 0 )
) `posts`
ORDER BY
SUBSTR(uid, 23, 6 )
offset 0
LIMIT 30
如上面的sql 所示,但请求列表的时候第一页我们可以随机生成0-32的数字作为SUBSTR(uid, {KaTeX parse error: Expected 'EOF', got '}' at position 6: start}̲, {len} ) 的len 的参数可以直接写死4-6位
//未传截取参数则重新生成
$subKey = $params['sub_key'] ?? 0;
if (empty($subKey)) {
$subKey = rand(0, 32);
}
接下来通过page更换offset 参数可以完美的分页
退出列表重新请求的时候重新重新截取字符排序又会获取不一样的数据并实现完美分页
我们这边测试数据是3万条
用rand() 分页llimit 10 offset 10000 需要 0.122~148s
用substr的形式分页llimit 10 offset 10000 需要0.082-0.084