2011-12-29 89 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

你可以做的是:

每當用戶更新時,您的郵件保存到特定於和當消息進來的時間戳的房間緩存,同時將其保存到當時的數據庫。當客戶端請求新消息時,如果用戶不是聊天室中的新用戶,則檢查用戶上次獲得服務器的時間,並從緩存中爲請求加載新消息。但是如果用戶是新的,那麼你可以從數據庫中爲他服務。

爲了在此方案中提高可伸縮性,您必須設置消息到期,以便消息可以在該時間後過期。或者實現一個基於時間戳刪除舊信息的異步​​方法。