SQL技术需求:随机取20篇文章并限制单用户文章数量上限
解决随机展示文章时单用户占比过高的问题
嘿,这个场景我之前做内容推荐的时候碰到过——既要随机选20篇文章,又得避免某个用户的内容霸屏,限制单用户最多3或4篇。下面给你几个实用的解决方案,适配不同的数据库版本:
方案一:用窗口函数(推荐,适合MySQL 8+/PostgreSQL等支持窗口函数的数据库)
这个方法逻辑清晰,性能也不错。先给每个用户的文章做随机排序,只保留前N篇(这里N是3或4),再从这些筛选后的文章里随机挑20篇。
WITH user_limited_articles AS ( SELECT a.article_id, a.user_id, a.title, a.description, -- 按用户分组,组内随机排序,给每条记录标序号 ROW_NUMBER() OVER (PARTITION BY a.user_id ORDER BY RAND()) AS row_num FROM articles a ) SELECT article_id, user_id, title, description FROM user_limited_articles WHERE row_num <= 3 -- 这里改成4就是限制单用户最多4篇 ORDER BY RAND() LIMIT 20;
原理说明:
- 第一步通过
ROW_NUMBER()窗口函数,把每个用户的文章随机打乱后编号,每个用户只保留编号≤3的文章; - 第二步从这些“按用户限制数量”后的文章里,再次随机排序取20篇,保证整体展示的随机性。
方案二:兼容老版本MySQL(无窗口函数/CTE支持)
如果你的数据库版本比较老,不支持CTE和窗口函数,可以用子查询的方式实现:
SELECT a.* FROM ( -- 先给所有文章生成随机值 SELECT *, RAND() AS random_score FROM articles ) a WHERE ( -- 统计当前用户下,随机值≥当前文章的数量,控制不超过3 SELECT COUNT(*) FROM (SELECT *, RAND() AS random_score FROM articles) a2 WHERE a2.user_id = a.user_id AND a2.random_score >= a.random_score ) <= 3 ORDER BY RAND() LIMIT 20;
注意事项:
- 这个方法因为每次子查询都要生成随机值,数据量大的时候性能会差一些,适合小数据量场景;
- 如果想改成限制4篇,把
<=3改成<=4就行。
额外优化建议
- 如果你的
articles表数据量很大,ORDER BY RAND()会导致全表扫描和排序,性能不佳。可以考虑用主键随机法替代,比如先随机生成一个主键范围,再筛选符合条件的文章,最后补全数量; - 如果存在“符合条件的文章总数不足20”的情况,业务上可以考虑放宽单用户限制,或者返回所有符合条件的文章,根据实际需求调整。
内容的提问来源于stack exchange,提问作者Mohan Jedaro
相关产品推荐
相关产品推荐

