文章表500万条数据,每天会有10万条数据更新,从更新的10万条中随机选3000条做数据研究,如果做到高效?
我的想法是另起一张表,存放今天更新的10万条都有哪些;
我只想到这个第一步,接下来该怎么做我还不知道怎么去实现;
假设按我这样的思路,我就算知道了每天更新的是哪10万条数据,那我还是得去500万条中找出3000条数据哦
不知道各位兄弟,有啥好的想法呢?
回复内容:
题目是一道面试题
我的想法是另起一张表,存放今天更新的10万条都有哪些;
我只想到这个第一步,接下来该怎么做我还不知道怎么去实现;
假设按我这样的思路,我就算知道了每天更新的是哪10万条数据,那我还是得去500万条中找出3000条数据哦
不知道各位兄弟,有啥好的想法呢?
10W中的3000条,概率是3%
那么只要在保存文章时,按照3%的概率,把本次更新文章保存到缓存中
这种缓存用redis的set类型最好,set类型不会保存重复的元素,所以文章反复更新也不会在列表里面产生多个结果
key的格式可以用"analyze:list:(Y-m-d)"
然后这个缓存可以设置为48小时过期,如果有需要的话,每天可以拿前一天的缓存归档到数据库
考虑到随机概率的误差,可以把3%放大到5%,最后肯定会记录得超过3000,但是也不会超太多,反正最后只拿3000条来用就行了
把每次更新都记录起来的话,无论是记录到缓存还是数据库,其实大部分的记录是没用的,不如按照概率先过滤一遍
其实记录每条文章的update_time也可以,我觉得where update_time >= ? and update_time
优点:
1、没有update_time字段也能玩,对现有表结构无要求,给生产环境的数据库加字段是件麻烦事
2、万一生产环境的数据库负载比较高,order by random()查询导致数据库卡死也不好,这样的话,最好是读写分离架构,在只读库上查询才行,产生了架构要求,我这个设计完全是个旁路记录,除了redis之外没要求
3、需要多少才记多少,额外IO少
一些粗陋的想法,仅供参考
分区
500万条,为了方便。根据数据的更新时间进行数据库分区(没用过mysql分区的看这个,在文章后面讲了),
比如说按照月份,我假设你这500万条数据是一年的,那么分成12份,每个区大约算42万条记录
这样,当使用更新时间进行搜索的时候,mysql就会根据你的更新时间 去选择分区,
也就是被搜索的数据是在这42万条里面去找(这肯定要比你在500万里面快多了,当然你要是按照天来分,那会更快)
加缓存
这没啥,就是你每天写入mysql的时候取3000条数据写入redis或者mongodb里面,做研究就不从mysql里面读了。用php从缓存里面读
多进程
你说的要做研究嘛,我假设你的研究算法很复杂。你去学学swoole,开三个进程,一个进程处理1000个数据,最后汇总结果
取出当日更新的10万
id放入一个数组在数组中随机取出3000个id
用select in读取指定的3000条记录
SELECT id FROM table WHERE date_refresh = 20120329
SELECT * FROM table WHERE id IN (id_0, id_1, id_2, ..., id_2999)
https://www.zhihu.com/question/20151242
首先,我会使用缓存的方式,将每天更新的数据的
主键
记录下来。从缓存中,随机获取
3000
个主键
拿着这3000 个主键,使用 IN 查询,获取对应的数据。
浅陋分析,勿笑。
1.获取id区间
select max(id) as max_id, min(id) as min_id
from (
select id from article_tb where update_time >= '2016-02-26 00:00:00'
)
update_time有索引,id为自增长id
2.随机获取
select *
from article_tb
where id >= min_id and id
查询3000次
// STEP 1 : 获取当天文章ID区间
// maxId -> select max(id) from news where 当天时间限定
// minId -> select min(id) from news where 当天时间限定
// STEP 2 : 取得随机ID
// 因为你一天有10万数据,数据总量有很高
// 所以避免使用MYSQL中的随机
$minId = 5000000;
$maxId = 5100000;
$i = 0;
$resultIds = [];
while(true){
$randId = rand($minId,$maxId);
if(in_array($randId, $resultIds)){
continue;
}
// 查询验证
// 根据你的需要验证数据是否是审核的呀,是否是正常数据呀
// 如果正常就载入到结果数组中。
$resultIds[] = $randId;
$i++;
if($i==3000){
break;
}
}
// 到这里结果已经有了
// 可以储存到结果集用其他方式分页进行研究或者浏览。