php如何搭建站内信系统及千万级用户站内信处理

原创 木鱼  2017-07-12 11:05  阅读 1,544 次

场景和需求

先说说站内信的场景和需求吧,后台管理员要给某用户多个用户推送一条站内信,用户可以对该站内信进行标记已查看状态。

怎么设计,才是最符合逻辑的?

我这里就大概说一下我个人的思路吧,答主的项目有用户自定义分组和多种用户类型,这里就说一下最简单也是最常用的情况吧。

用户量少

逻辑简单最容易理解操作的,用户在几十到上百的时候,可以使用。

站内信表letter

idmanager_id(管理员id), user_id(为0则是全部用户),content(站内信内容),status(状态查看状态),create_at(发送时间)

管理员插入的时候需要遍历用户表,查询出所有的用户id,如果用户有30个,则插入30条站内信到letter表。

 

这种的设计弊端显而易见,当用户量多的时候,发送一次站内信,要重复插入几百上千条站内信数据,损耗空间,性能。

 

中量用户

当用户量有几百上千的时候,第一种方法就可以不用考虑了。

此时我们可以把letter表拆分为两张。

表名:letter

idmanager_id(管理员id),content(站内信内容),create_at(发送时间)

表名:letter_status

iduser_id(用户id),status(状态查看状态)

 

把站内信的主题内容放到letter表里面,把用户的查收状态放到letter_status表里面,可以避免大量的数据的重复插入,比如content字段,管理员如果给所有用户推送一条300汉字的站内信,假设有用户10000个,一个汉字两个字节,300个汉字有600个字节,600字节x10000=6000000字节,约5.7M数据,一个站内信瞬间就要插入几M的数据,实在是有点过分吧。。

 

千万级用户

当用户量很大的时候,第二种方法也不行了,因为但凡每个系统,都有大量无效用户,即长期不在线之类的这种的。

那我们每次还要给他插入一条状态数据,是不是很没有必要?

表名:letter

idmanager_id(管理员id),user_id(用户id,为0则是全部用户),content(站内信内容),create_at(发送时间)

表名:letter_status

iduser_id(用户id),letter_id(站内信的id),status(状态查看状态)

 

letter表的user_id字段,需要存储为id,id,id的格式,例如3,15,23,45,把用户的id已逗号分隔的形式存储。

letter_status表不操作。

 

这样,当用户登录的时候,证明该用户为有效用户,查询遍历letter表,查询user_id为0或者当前用户id在user_id中的站内信,可以用mysql的find_in_set('str', filed)查询。

比如当前用户的id为1;

SQL语句:

SELECT * FROM `letter` WHERE user_id=0 OR find_in_set(1, user_id);

查询出来存在有站内信后,查询letter_status是否已经存在该条站内信,并且user_id是否为当前用户。 如果不存在,则插入一条到letter_status,这样用户就有一条未读站内信了。

 

也可以用关联查询:

SELECT `letter`.*,`letter_status`.id AS status_id FROM `letter` LEFT JOIN `leter_status` ON `letter`.id=leter_status.letter_id 
WHERE `letter`.user_id=0 OR find_in_set(1, `letter`.user_id);

查询出来数据集后,遍历所有查询出的站内信,判断status_id是否为空,如果为空,就插入这条站内信的内容到ld_status里面,两种SQL查询的方式不同,不过只是把两次查询简化成了关联查询,但是达到的目的都是一样的。

 

 

好了,站内信基本就是这么个情况了,大家也可以根据自己的情况筛选不同的用户,给用户分组等。

本文地址:https://www.m5yu.com/letter.html
关注我们:请关注一下我们的微信公众号:扫描二维码,公众号:木鱼博客
版权声明:本文为原创文章,版权归 木鱼 所有,欢迎分享本文,转载请保留出处!

发表评论