在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
在很多网站系统(如CMS系统,SNS系统等),都有“站内信”的功能。 “站内信”不同于电子邮件,电子邮件通过专门的邮件服务器发送、保存。而“站内信”是系统内的消息,说白了,“站内信”的实现,就是通过数据库插入记录来实现的。 “站内信”有两个基本功能。一:点到点的消息传送。用户给用户发送站内信;管理员给用户发送站内信。二:点到面的消息传送。管理员给用户(指定满足某一条件的用户群)群发消息。点到点的消息传送很容易实现,本文不再详述。下面将根据不同的情况,来说说“站内信”的群发是如何实现的。 第一种情况,站内的用户是少量级别的。(几十到上百) 这种情况,由于用户的数量非常少,因此,没有必要过多的考虑数据库的优化,采用简单的表格,对系统的设计也来的简单,后期也比较容易维护,是典型的用空间换时间的做法。 数据库的设计如下:表名:Message ID:编号;SendID:发送者编号;RecID:接受者编号(如为0,则接受者为所有人);Message:站内信内容;Statue:站内信的查看状态;PDate:站内信发送时间; 如果,某一个管理员要给所有人发站内信,则先遍历用户表,再按照用户表中的所有用户依次将站内信插入到Message表中。这样,如果有56个用户,则群发一条站内信要执行56个插入操作。这个理解上比较简单,比较耗损空间。 某一个用户登陆后,查看站内信的语句则为: Select * FROM Message Where RecID=‘ID’ OR RecID=0 第二种情况,站内的用户中量级别的(上千到上万)。 如果还是按照第一种情况的思路。那发一条站内信的后果基本上就是后台崩溃了。因为,发一条站内信,得重复上千个插入记录,这还不是最主要的,关键是上千乃至上万条记录,Message字段的内容是一样的,而Message有大量的占用存储空间。比方说,Message字段有100个汉字,占用200个字节,那么5万条,就占用200×50000=10000000个字节=10M。简单的一份站内信,就占用10M,这还让不让人活了。 因此,将原先的表格拆分为两个表,将Message的主体放在一个表内,节省空间的占用 数据库的设计如下: 表名:Message ID:编号;SendID:发送者编号;RecID:接受者编号(如为0,则接受者为所有人);MessageID:站内信编号;Statue:站内信的查看状态; 表名:MessageText ID:编号;Message:站内信的内容;PDate:站内信发送时间; 在管理员发一封站内信的时候,执行两步操作。先在MessageText表中,插入站内信的内容。然后在Message表中给所有的用户插入一条记录,标识有一封站内信。 这样的设计,将重复的站内信的主体信息(站内信的内容,发送时间)放在一个表内,大量的节省存储空间。不过,在查询的时候,要比第一种情况来的复杂。 第三种情况,站内的用户是大量级的(上百万),并且活跃的用户只占其中的一部分。 大家都有这样的经历,某日看一个网站比较好,一时心情澎湃,就注册了一个用户。过了一段时间,由于种种原因,就忘记了注册时的用户名和密码,也就不再登陆了。那么这个用户就称为不活跃的。从实际来看,不活跃的用户占着不小的比例。 我们以注册用户2百万,其中活跃用户只占其中的10%。 就算是按照第二种的情况,发一封“站内信”,那得执行2百万个插入操作。但是其中的有效操作只有10%,因为另外的90%的用户可能永远都不会再登陆了。 在这种情况下,我们还得把思路换换。 数据库的设计和第二种情况一样: 表名:Message ID:编号;SendID:发送者编号;RecID:接受者编号(如为0,则接受者为所有人);MessageID:站内信编号;Statue:站内信的查看状态; 表名:MessageText ID:编号;Message:站内信的内容;PDate:站内信发送时间; 管理员发站内信的时候,只在MessageText插入站内信的主体内容。Message里不插入记录。 那么,用户在登录以后,首先查询MessageText中的那些没有在Message中有记录的记录,表示是未读的站内信。在查阅站内信的内容时,再将相关的记录插入到Message中。 这个方法和第二种的比较起来。如果,活跃用户是100%。两者效率是一样的。而活跃用户的比例越低,越能体现第三种的优越来。只插入有效的记录,那些不活跃的,就不再占用空间了。 以上,是我对群发“站内信”的实现的想法。 一篇文章: 站内短信很常见,比如系统需要发消息给用户,用户登录之后可以看到这些消息。 Msg表,字段如下: id int 自增长id 一张user_has_msg表,字段如下: id int 这样设计是基于如下考虑的: 首先,msg表包含了发件箱所需要的所有信息,程序的时候写发件箱的时候可以只考虑操作一张数据库表。 第二,user_has_msg中,departmentid主要考虑的是存在大量的按照部门群发的可能,这样的话,群发给一个部门的时候之需要在两张表上个记录一条数据,而不需要在user_has_msg中记录该部门员工数条记录。 但是,后来这个方案被我自己和同事讨论后否决了,原因如下: 首先,departmentid的存在使得没有用户可以删除收件箱中的站内信,因为删除了,其他人的收件箱里也看不到。 第二,msg表不能保证显示完所有的发件箱所需要的数据,因为只有着一张表的是后读不出来收件人信息。 修改后的版本是: 将msg修改为只保纯粹的信息的表: id int 自增长id 将user_has_msg修改为保存各种关系和状态的表: id int
进一步:http://blog.rexsong.com/?p=1202 http://www.nowamagic.net/librarys/veda/detail/431 http://www.cnblogs.com/hejiaquan/archive/2012/04/07/2435817.html http://baiyuxiong.iteye.com/blog/876211 http://huoding.com/2012/09/28/174 --------------------------------- 一篇文章: 需要做一个站内信的功能,可是群发不知道怎么弄,求帮助 或者谁有例子可以给参考一下?
php
解决方案 » 上面的的思路跟游戏中的邮件是一样的:
邮件需求:
根据需求,邮件共分两类,即个人和系统,个人类型邮件是面向个人的,而系统类型邮件向所有玩家投递的。个人类型的邮件信息单一,每一封邮件的接收者都需要做一条完整的数据记录,而系统类型的邮件信息的内容一致,如果像处理个人类型邮件一样,那就会出现大量数据冗余,从而造成数据库容量浪费,从这点角度出发,我准备对mysql数据库里的邮件做以下设计。
创建两个表,一个是个人类型表person_mail,另一个系统类型表system_mail,person_mail表用来存储所有玩家的个人邮件记录,system_mail表用来存储系统邮件记录,然后在玩家基本信息表(比如取名user_baseinfo)里再加一个字段"sysmail_receiveidx",用来表示系统类型邮件的历史领取索引标记,该值初始为0,表示没有领取过系统类型邮件。
模拟个示例场景:
游戏刚开服,服务器的添加了10封新的系统邮件,玩家登入服务器,拉取邮件列表数据时,都会拿sysmail_receiveidx的值和system_mail表里的邮件索引(即id,id设定的是增量值)做比较,把大于该值索引的系统类型邮件挑出来,然后把插入到person_mail表里,且将sysmail_receiveidx字段值设置为当前system_mail表里邮件索引的最大值。
考虑系统类型邮件数据的可共用性,所以执行这类插入操作时,从system_mail表筛选出来的每条邮件记录只做轻量拷贝,比如类型、创建时间和邮件发送者,然后把邮件接收者填充为本次操作的玩家用户ID,邮件索引用原始值与用户id通过算法生成一个新的唯一值。至于标题、内容和相关奖励数据因占用容量较大我们不进行拷贝,而是等客户端请求个人邮件列表数据时,如果是系统类型邮件,就需要去system_mail表里把对应的记录行取出来,根据记录,把邮件的标题,内容和相关奖励数据填充完整,这样就有效节约了不必要的冗余容量消耗。
|
2022-08-17
2022-11-06
2022-07-18
2022-08-18
2022-07-29
NO1.给所有的用户‘真的’发送一个信息。
NO2.在用户登录时,获取程序的待办任务。
发布消息的并发不会太大,数据量大可以按时间分表,只关心近期的
也可以使用redis