排行榜設計

最近在做排行榜功能,排行榜無非就是對用戶一些數據的排序,在量級不是很大的情況下還是比較簡單的,在數據結構上使用數組,set,map都可以,依具體情況而定,這裏不做過多討論。現在遇到的問題是在數據庫方面的,也就是對排行榜數據該已什麼方式進行存儲。

我們用的數據庫是mysql,如果排行榜量級在百名之內的話可以把每個進榜用戶的數據都當做是一條數據庫記錄插入表中,因爲數據量級比較小,插入刪除操作不是太多,對數據庫的壓力不是很大(定時存儲還是要做的,減少對數據的操作頻率)。數據庫表設計大概是這樣的:

+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| ranktype  | int(10) unsigned    | NO   | PRI | NULL    |       |
| order     | int(10) unsigned    | NO   | PRI | NULL    |       |
| id        | int(10) unsigned    | NO   |     | NULL    |       |
| data      | blob                | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+
order記錄用戶名次,data保存用戶數據,如果用戶數據較少的話可以不用blob,而是單獨拿出來存,這樣會更直觀。

  這樣存儲明顯有個問題,就是當一個人的名次變了,可能會影響到其他很多人的名次,例如一個用戶從300名上升到了100名,這時候相當於從300名到100名的所有用戶都變了,也就是說這個時候需要更新200條數據庫記錄。排行榜名次很多的話這顯然是不可接受的,因爲如果排名有幾萬名,這種變動一次就有可能在幾千名。

我們要做的排名正是有幾萬名的,所以要做其他方案。從上面可以發現對數據庫造成壓力的地方其實就是一次需要更新的數據記錄太多,所以可以從減少更新記錄來入手。在之前項目中我們的做法是把排行榜分成幾段,每段存成數據庫中的一條記錄。表是這樣的:

+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| ranktype  | int(10) unsigned    | NO   | PRI | NULL    |       |
| id        | int(10) unsigned    | NO   | PRI | NULL    |       |
| data      | blob                | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+
id表示這是排行榜的第幾段,好比排行榜有1w名,分成10段,每段1000名,id爲1的就存1到1000名,id爲2的存儲1001到2000名,以此類推。

這樣的話如果排行榜有變化只需要一條或者有限的幾條記錄就好了,數據庫幾乎沒有壓力,但是這種方案不好的地方在於不直觀,從數據庫層面上你沒法知道名次信息,而且以後如果有合併數據的需求的話單從數據庫層面是沒法做到的(必須通過程序讀出數據解析然後合併最後再存到數據庫)。

爲了解決上面的問題,有了第三種設計方案:

+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| ranktype  | int(10) unsigned    | NO   | PRI | NULL    |       |
| id        | int(10) unsigned    | NO   | PRI | NULL    |       |
| pkpara1   | bigint(20) unsigned | NO   |     | NULL    |       |
| pkpara2   | bigint(20) unsigned | NO   |     | NULL    |       |
| pkpara3   | bigint(20) unsigned | NO   |     | NULL    |       |
| data      | blob                | YES  |     | NULL    |       |
+-----------+---------------------+------+-----+---------+-------+
ranktype(排行榜類型),id(用戶id),pkpara1 2 3 4(競爭參數),data(用戶數據)
這種方案的思想就是在數據庫中不存在名次,只是存儲排行榜中的用戶數據。當程序啓動的時候從數據庫中一次把數據全部讀出來,然後按照pkpara1 2 3 4進行排名,這樣在內存中就能構造出一個排行榜了。如果有用戶新進榜只需要簡單的對其進行pkpara的賦值,然後可以直接插入數據庫,並不需要擔心數據庫中其他用戶的數據。如果有名次的變化也只是對造成變化的那個用戶的pkpara進行更新,其他的互不影響。用戶掉出排行榜也只是從數據庫中刪除一條記錄。當然操作數據庫數據之前要記得更新內存中的排行榜數據。

可見這種方案可以滿足大多數需求,但是它需要常駐內存,不然無法更新排行榜,不過在排行參數不大的情況下維持一個幾十萬甚至幾百萬的排名還是可以的,有待改進…………

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章