2011-12-29 87 views
2

对于我的大学项目,我正在开发一个包含房间,用户注册等的动态即时聊天网站。我已经将整个系统计划在一个方面。房间。我很困惑如何设计房间数据库。与房间实时聊天项目的数据库模式

从透视角度看,房间是由当时是该房间的操作员的用户创建的。用户可以加入房间并在其中进行交谈。该系统必须具有可扩展性,如果不是每天发送数百万条消息,则该系统必须占据数十万个。

本来,我打算在我的数据库名为messages创建表,并且有场这样的:

| r_id | u_id | message | timestamp |

r_idu_id将外键分别房间ID和用户ID。这样做意味着我需要在用户发送消息时插入一条新记录,并定期为每个客户端运行一条SELECT语句(比如说每隔3秒左右)获取最近的消息。我担心这是因为表格会很大,运行这些语句可能会产生很多开销并需要很长时间。

我想实现这个的另一种方式是为每个房间创建一个新的数据库表。假设一个用户创建3个房间叫GeneralProgrammingGaming,数据库表会是什么样子:room_generalroom_programmingroom_gaming,每个像场:

| u_id | message | timestamp |

这将大幅上查询量减少对于每个表格,但是当我编程时可能会引入问题。

所以,我坚持要做到这一点的最佳方式是。如果它有所作为,我使用的技术将是使用PHP的MySQL,以及完整的AJAX。

感谢您的帮助!

回答

2

为每个房间创建一张桌子是个坏主意。很难实施和难以支持。

不要担心选择的性能,因为他们将WERY简单:

SELECT * FROM messages WHERE r_id=X ORDER BY timestamp DESC LIMIT X,Y 

只要确保你的(R_ID,时间戳)在此为了使这个选择使用索引收录在一起:

ALTER TABLE `messages` ADD KEY `IN_messages_room_time` (`r_id`, `timestamp`); 

如果你仍然有性能问题(可能你不会),只需添加1-3秒内存缓存(使用内存缓存),每1-3秒读取从DB一次一个消息。

也看看阿波罗克拉克的答案:https://stackoverflow.com/a/8673165/436932,以防止存储大量的不必要的旧信息:你可以把它放到MYISAM表archive或干脆删除。

+0

完美答案,memcached和表上的索引似乎是最好的方法:) 谢谢。 – 2011-12-29 21:21:58

1

查找到存储的信息创建一个“事务表”。基本上,您需要决定,我是否真的想记录发布到房间的所有消息,或者只是上个月/周/日/小时发布的消息。如果你真的想要记录每条消息的历史记录,那么你将创建两个数据库。如果你不想保留每条消息的历史记录,那么你只需要一张表。

使用事务表,这里怎么会流:

  1. 用户进入聊天室
  2. 用户类型的消息,该消息被保存到事务表。
  3. 每500毫秒或3秒,屋里的每个用户将查询交易表,从过去的500毫秒或3秒

    SELECT * FROM message_transactions WHERE timestamp > 123456789 
    
  4. cron作业获得最新的更新运行每5分钟或1小时,删除所有大于5min的条目,或者您希望历史记录长的条目。

一定要同步,圆每一个用户查询事务表,从而使MySQL查询结果缓存会一命呜呼。例如,圆时间戳每隔1秒或每500毫秒的时间。

什么现在要发生的是用户只能得到最新的消息,并随着时间的推移你的数据库不会在规模爆炸,或减慢。这样做,您需要在JS中缓存客户端消息的历史记录。

在另一面,你可以只得到一个PHP到IRC库,并收工。另外,如果您对此感到好奇,请查看Facebook如何实现基于AJAX的聊天系统。

1

为了加快您的数据库,看看你的索引表:http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

在你的情况我认为你会通过R_ID可以选择邮件,而这样做,通过U_ID用户表的连接。我会索引r_id和u_id列。我并不是这方面的专家,因为我只为我自己的项目做过“有用的事情”。我不明白每一个索引的亲和关系,只是索引那些通常被用作索引的列会加快速度。谷歌“mysql索引教程”,你会发现更多的信息。

不要去坚果和索引的每一列,您会在INSERT和UPDATE放缓。

我也建议你清除聊天记录每隔数天/周,或将它们移动到另一台服务器进行存档,如果这就是你想要/需要做什么。

+0

r_id和u_id将被自动索引,因为它们是外键。简单的JOIN用户有一个坏主意。如果表格'messages'很大,作者必须首先检索所有消息,然后将用户加入结果集。类似这样的:SELECT * FROM(SELECT messages ...)as msg_limited JOIN users ON msg_limited.u_id = users.id – 2011-12-29 20:47:50

+0

我正在使用JOIN作为例子,但你仍然是对的。在思考之前发帖并不成功。 – TPC 2011-12-29 20:50:12

+0

发布此评论后,我怀疑..我一个星期前有同样的问题,但现在我看了看查询,并看到描述的解决方案(subselect)可能不工作,因为我没有使用它。相反,我不得不运行2查询:一个用于ids,第二个用于所有连接和entity.id IN(1,2,3等...) – 2011-12-29 21:02:23

0

你可以做的是:

每当用户更新时,您的邮件保存到特定于和当消息进来的时间戳的房间缓存,同时将其保存到当时的数据库。当客户端请求新消息时,如果用户不是聊天室中的新用户,则检查用户上次获得服务器的时间,并从缓存中为请求加载新消息。但是如果用户是新的,那么你可以从数据库中为他服务。

为了在此方案中提高可伸缩性,您必须设置消息到期,以便消息可以在该时间后过期。或者实现一个基于时间戳删除旧信息的异步​​方法。