当前位置:Gxlcms > PHP教程 > 文章表500万条数据,每天会有10万条数据更新,从更新的10万条中随机选3000条做数据研究,如果做到高效?

文章表500万条数据,每天会有10万条数据更新,从更新的10万条中随机选3000条做数据研究,如果做到高效?

时间:2021-07-01 10:21:17 帮助过:46人阅读

题目是一道面试题
我的想法是另起一张表,存放今天更新的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 <= ? order by random() limit 3000差不多就行了,反正每天才跑一次而已,不过既然是面试的话,怎么能不秀秀思路呢

优点:
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个数据,最后汇总结果

  1. 取出当日更新的10万

  2. id放入一个数组在数组中随机取出3000个id

  3. 用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 < ( rand()*(max_id-min_id)+min_id ) limit 1

查询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;
    }
}

// 到这里结果已经有了
// 可以储存到结果集用其他方式分页进行研究或者浏览。

人气教程排行