程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 用戶參與記錄存儲的演變

用戶參與記錄存儲的演變

編輯:關於PHP編程

有這樣一個應用場景:用戶有兩個連續的操作A和操作B,必須是操作A完成後才能執行操作B,如果操作A沒有完成就觸發了操作B,則顯示用戶需要先執行操作A,即在操作B執行需要查詢操作A是否執行過。這裡引申出來的問題是,記錄用戶參與記錄,提供針對用戶和操作的查詢方法。當不同的數據量時,我們的存儲方案會大不相同,隨著數據的增長,方案不斷演變。

1、數據量較小,用戶操作行為固定:
存儲:MySQL
方案:我們以UID為key,一行一個用戶,每個用戶包括的用戶作為列存儲,比如UID=100,固定存儲為操作A和操作B,則表結構大致如下:
table_operation
uid operation_a operation_b
100 1 1

如果我們要查詢用戶是否參與A或B時,直接使用SQL: SELECT * FROM table_operation WHERE uid=100 AND action_a=1就可以達成目標。

問題:用戶操作固定,擴展較難,如果需要增加用戶操作行為,則需要增加字段或增加表存儲,增加字段的方法在一定的數據量級以下(比如100萬)是可行的,如果行為間無關,則增加表存儲方案的表現會很不錯。

2、數據量較小、用戶操作行為不固定:
與場景1相比,當前場景除了uid這個變量,增加了用戶操作變量,即我們需要關注用戶和用戶操作兩個變量。
存儲:MySQL
方案1:增加操作表,生成操作id,用戶操作行為表存儲uid和oid。當用戶執行一個新的操作時就在操作行為表插入一條記錄。其表結構大致如下:

table_operation_info
oid name
1 operation_a
2 operation_b

table_operation
uid oid
1 1
1 2

當需要查詢用戶1是否執行過操作A時,使用SQL:SELECT * FROM table_operation WHERE oid=1 AND oid=1。
問題:當用戶的操作行為較多時,用戶操作行為增長速度很快,數據量也為逐漸增大,可能MySQL單表無法負載。解決方案在後續場景中說明。

3、數據量較大,用戶行為固定
存儲:MySQL
方案:與場景1相比,當前場景不同在於數據量比場景1大,數據量大到MySQL單表負載不過來。此方案解決的就是這個問題,當單表太大時,性價比較高的方法一般是采用分表。我們當前場景的變量是uid,只要依據uid按水平分表即可。

4、數據量較大,用戶行為不固定
存儲: MySQL
方案1:此方案應用於用戶的操作行為可以分類的情況,即在場景1的基礎上增加兩次分表操作,按操作行為類分表和按用戶分表。當前方案中我們需要應對兩個變量:操作行為和用戶。兩次分表分別對應這兩個變量,按業務規則做操作行為的分表操作,按用戶id水平切分減少數據量。

方案2:此方案是完全的水平分表操作,在場景2的方案基礎上,按用戶水平切分。

5、數據量超大
存儲: MySQL
方案1:分庫分表,此時一個庫已經無法滿足需求,規則依據前面的場景實現,根據實際的需求可以考慮把不同的庫放不同的機器上。
方案2:在分庫分表的基礎上,按位存儲,因為一個操作行為有沒有執行過是一個是否的狀態,即0,1狀態,因此我們可以用一個位來存儲,64位可以存儲64個操作行為的標記。

其它存儲
key-value數據庫
我們的需求實際上並不需要太多的關系型數據庫的功能,簡單的 k-v數據庫就可以實現我們的功能,並且在性能上也會有所提升,畢竟做得少,會快。
先不管是選擇基於內存的,還是非內存的(可以根據實際需求來選擇,也可以是熱點數據在內存,沉默數據在非內存中),假設我們有足夠的空間存儲。
方案1:
以uid+oid為key,值可以存儲狀態,也可以只存儲是否參與(0和1),但是會存在key太多的情況,特別是當數據量超大時,uid的個數*oid的個數,可能是你無法相像的量級。
方案2:
一般來說,用戶操作行為的數據量完全小於用戶的量級,並且用戶操作行為的數據可控。如果要減少key的個數,我們可以使用oid+用戶分區索引id作為key,這裡所謂的用戶分區索引是指將用戶以某個數量分成一個區,所有的用戶都記錄在這個這個區間內,比如以10000為一個區間,則uid為1到9999的用戶分到區間0,這裡可以以1和0存儲用戶是否執行了此操作,一個key對應的value初始化存儲10000個0。當uid=100的用戶執行了某操作,則將第100個0置為1。
方案3:
在方案2的基礎上,將10000個0轉換為10000個01位,假設一個位存儲50位,則總共只需要200個。
方案4:
當用戶量超大時,大多數的用戶對於某個操作可能都是沒有參與的,則在方案3的基礎上我們增加簡單的稀疏矩陣壓縮,給每個存儲位添加索引,當存儲值不為0時才會存儲。
方案5:
我還沒想到,期待你的分享

小結

•隨著數據量的增大,總的思路是分冶,當一個表搞不定時分表,當一個庫搞不定時分庫,當一台機器搞不定時加機器。
•對於不同的存儲介質選擇需要考慮成本和需求,所有的選擇都是平衡後的結果。
•節省空間,按位存儲。
•不要過早優化。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved