天天看點

關系型資料庫中好友關系的設計

  接到需求,設計一群注冊使用者的好友關系,各自要能查詢到自己的好友清單。最早想過用圖資料庫來進行好友關系存儲,但身邊沒有成熟的案例,網上的資料也比較少。是以還是決定采用傳統關系型資料庫MySQL來進行設計。

  好友關系,如果簡單設計成一張表的話,随着注冊使用者的增多,好友關系勢必會呈指數級增加,當系統中使用者為10個人時,那麼完全添加好友的話,關系資料(假設A和B是好友隻有一條資料)則為(9+8+...+1)即55條;當系統中注冊使用者的數量增長到1000個人時,關系資料最大值為(999+998+...+1)即499500。是以如何設計系統,讓使用者快速查詢到好友關系,是個難點。

  這裡給出一種思路:根據注冊使用者的某一個字段(如使用者ID),将它的所有好友關系集中存放到一張表中,而不同的使用者,會根據這個ID的不同,将它們的好友關系分别散列在不同的資料表中。這樣達到了将資料表資料分散,減輕單表壓力的目的。但是,按照這個思路設計時,好友的關系必須是雙向的,否則A和B的關系,到底是以A的ID進行散列還是B的ID進行散列呢?這樣一來,好友的關系數增加了1倍,但是如果散列的足夠均衡,這個結果也是可以接受的。市面上很多好友關系在進行設計時,也是采用雙向的方式,即A加了B,B同意之後,即建立了雙向好友關系,當A删除B的好友關系時,B查詢自己的好友清單時,會發現A還在,隻有B再删除A,雙向的好友關系才會消除。

  接下來的工作是如何将這個散列方案實施下來。這裡有兩個問題,一個是在初期規劃時,我們可能并不知道這個社交群體最終的規模,即無法在初期就建立固定數量的關系表,這個表一定是當容量達到一定規模時動态增長的;第二個是,在追求每張表的資料均衡時,我們還要考慮一種情況,即如果初期存入的一批使用者被散列到某張表中(即該批使用者指向的好友關系存在該表中),而恰好該批使用者的好友關系增長速度遠遠超過其他批次的使用者,造成該表資料急速增長的情況,該如何處理?在此背景下,我們來考慮這個被散列計算的字段該怎麼設計。

  對于以上問題,一個簡單的思路如下:假設現在有t_a,t_b,t_c,t_d四張表,都用于存放關系,在它們遠沒有達到存儲規劃上限時,我們可以就簡單根據現有的各自表的容量,來決定注冊使用者該字段計算出來該指向哪張表。比如a,b,c現在容量都達到了1000條,而d表的容量才100條,那麼在注冊使用者時,我們就将使用者該字段設計成計算結果指向d表。我們還可以設計一個容量因子,在單表數量超過預設上限*該容量因子(如0.7)時,即停止将新使用者的字段值設計成計算結果指向該表。另外,如果我們設定一個好友關系上限,如最多500個好友,那麼預設的表資料上限除以這個數量限制可以得到這張表最多存放多少個不同的使用者,這種做法可以保證這些關系表數量不會異常增長到超過我們預設的上限。

  但是,如果我們的系統允許使用者無節制的增加好友,那麼當使用者量不斷增長時,上述方案就無法在系統規模不斷增長之後還能保證單表關系數量不會突破限制。此時,限制一個使用者所有的好友關系在某個單表的方案已經不現實,但我們還是應該盡量這麼做,對于單個使用者在單表中設定一個關系數量上限,當他的好友關系超過這個數量時,把它存在另外一張表中。那麼,如何知道這個使用者是否圖破了單表存儲的設定上限,擁有多張表存儲了好友關系,我們可以在注冊使用者的字段時加一個标記字段,那麼查到該使用者即可知道這個資訊,對于已經突破了單表設定上限的,我們可以再加一張表-突破關系存放表,某使用者突破一次,那麼在該表中即存一條資料,其中一個字段的值與該使用者原先的散列計算值比對起來可以确定這次突破後存放的新表名稱。這樣既可快速定位到這些新表的名稱,進而查詢出所有的好友關系,另外,好友關系表中對單表單使用者的好友關系數量做出了限制,是以當有N個表存放了該使用者的資料時,那麼好友的數量即,(N-1)*固定容量+第N張表的好友數量,是以統計好友總數也不複雜,隻需要知道第N張表的數量即可推算出總數。

  暫時想到這麼多,歡迎評論留言補充思路或者其它拓展點。