欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP+MySQL 千万级数据处理案例(一)(分表)

程序员文章站 2022-03-10 11:43:01
场景 一个金融公司有 500w 投资用户,每天充值投资 50w 笔,那么该公司每年将近有 1 亿条充值记录,那么我们改如何处理这个充值订单表的数据呢?难不成都放一张表里面,那万一哪天我让你去统计满足某个需求的记录,1 亿条数据里面检索你会累死 mysql 的!今天我们就来讲述一下如何去处理这种情况。 ......

场景

一个金融公司有 500w 投资用户,每天充值投资 50w 笔,那么该公司每年将近有 1 亿条充值记录,那么我们改如何处理这个充值订单表的数据呢?难不成都放一张表里面,那万一哪天我让你去统计满足某个需求的记录,1 亿条数据里面检索你会累死 mysql 的!今天我们就来讲述一下如何去处理这种情况。

 

mysql 分布式之分表思路

分表不是随随便便就分表,必须要结合项目的实际情况,比如我们的项目的瓶颈在哪里,区区几千几万几十万或者几

百万的数据用分表那就是高射炮打蚊子了,不要盲目的分表!必须要达到一定的数量级,并且影响了我们的用户的访问速度,性能下降的情况下才能考虑去做分表处理!

画个简单的不能再简单的图吧

 

PHP+MySQL 千万级数据处理案例(一)(分表)

分表的思路就是如此简单,借助中间件可以根据不同省份的订单插入到不同省份对应的表当中去,当然实际当中还得要结合自身的业务来寻找制作这个中间件,不要照搬人家的逻辑思路!

mysql 分布式之分表实战(插入总表分然后取模分发到分表)

//伪代码
//假设用户数据入库 定为每天50w的数据量入库
//我们创建一张用户主表+两张用户分表  用户分表user0 用户分表user1
//首先所有用户数据入用户主表
$sql = insert into users(a,b,c) values($a,$b,$c);
$res = $model->query($sql);
if($res){
    //获取user主表插入的最后一条sql的id
    $insert_id = $model->getlastinsid();
    //对刚才入库成功的记录的id取模 如果你是两种用户分表那么就%2如果是200张那么就%200
    $d = $insert_id%2;
    //取模之后 获取到最后的模 任何数对2取模那么不是0就是1 任何数对200取模那么模就是0到200之间
    //插入到不同的用户分表当中去
    $_sql = insert into user{$d} (a,b,c) values($a,$b,$c);
    $ru = $model->query($_sql);
}

  

其实我们是利用了取模的形式做了一个中间件的功能,根据模的数值去往不同的 user0 还有 user1 当中插入数据,达到了分发的效果

整个过程 user 主表一定是先插入数据的,然后根据模再去往不同的分表里面插数据;

需要强调的是 user 分表里面的 user_id 主键一定不是自增的,一定是根据 user 主表里面的 id 来插入的,必须保证和主表里面的主键 id 保持一致!

需要强调的是 user 主表和 user0 user1 分表一定是字段属性相同的直接复制即可,只是把数据分发到不同的表里面去了,这也叫水平分表!

 

在做 mysql 的水平分表的时候要记住,潜规则,默认的新增的时候我们插入到 user 主表然后根据取模插入到不同的分表里面去,但是删除,修改,查看,都和主表没关系了,主表只有在新增的时候往里面写入数据根据 id 取模再分发到不同的分表里面去!当然主表也可以做一些其他方面的统计。

 

mysql 分布式之分表实战(修改查看删除分表数据)

上边我们讲过,修改删除查询的时候直接操作的是分表,不再去动主表

//伪代码
$id = $_post['id'];
//对主键id取模从而来判断操作哪张分表
$d = $id%2;
$sql = update user{$d} set username='{$username}',age='{$age}' where id = $id;
$model->query($sql);

  

修改删除也是根据主键 id 对其取模确定下来针对哪张分表进行修改或者删除

但是我们删除或者修改了那么主表里面的数据也就和分表里面的不一致了啊,如何保证主表和从表数据一致呢?

很多人会想在操作完分表之后立马去操作主表做修改操作不得了,也行啊!但是不感觉浪费吗?如果你学会了协程那么可以起一个协程去操作主表即可,或者起一个异步 task 任务去操作主表也可以,都是异步执行不影响程序的执行,这是非常好的做法,前提是你得懂什么是协程以及 swoole 里面的 task 异步任务,之前博客里面有讲,可以去翻翻我的博客。

另外还有一种老套的方式就是利用队列的形式,不,不,不,不,不叫队列,redis 里面的 list, 充其量叫列表,redis5 才新增了一种新的类型 stream 类型那才是真正的队列,是相当于乞丐版的 kafka, 利用 redis 里面的 list 类型,将修改分表的 sql 语句改成修改主表的 sql, 条件一直 id 一直 只是操作的表为主表即可,然后塞到 list 列表里面去 lpush 然后弄个定时任务 rpop 去更新主表即可!这种方法很笨哦,但是也管用!

 

刚开始就说了一定要结合实际的业务需求,我们上边讲到的是按照主键 id 进行的数据的分发到不同的分表当中,所以不管是查询修改还是删除都要结合主键 id 去确定要操作的分表才行,有一定的局限性,但是我们的实际业务就是这么设计的,所以还是那句唠唠叨叨的话,一定要结合自己的实际业务需求;

 

分表并不是最优的解决方案,并且在实际的应用当中使用不不是很广泛,存在就有道理,主要还是看你的业务需求啦哦!

更多学习内容请访问:

腾讯t3-t4标准精品php架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新)PHP+MySQL 千万级数据处理案例(一)(分表)