[Redis] 如何設計Redis的KEY
REDIS KEY DESIGN
現在有bankid username password balance 四種欄位
1.用Hash來設計的話,結構如以下:
key field value field value …
用bankid來當key值,後面接欄位與值,故查詢時可直接用ID查KEY 接著取欄位值
一次建立多個欄位的方法為HMSET,取得特定欄位值的方法為HGET,文件有詳細說明
bankid username $username password $password balance $balance
2.用List設計的話,結構如以下:
key value value …
key value value …
bankid $id $username $password $balance
這邊需要考慮到如果餘額是歷史交易的餘額,而不是作為最終餘額的話就可以用LIST,
不然LIST缺乏field name 更改值的同時又要保持順序不太方便,
畢竟LIST取值的時候因為沒有欄位只能靠index索引,順序打亂很麻煩,
否則就是要在value命名上動手腳來辨識。
不然LIST缺乏field name 更改值的同時又要保持順序不太方便,
畢竟LIST取值的時候因為沒有欄位只能靠index索引,順序打亂很麻煩,
否則就是要在value命名上動手腳來辨識。
3.用單一KEY來儲存
把bankid的每個欄位都獨立成一個KEY,結構如下:
key value
bankid $id
bankid:username $username
bankid:password $password
bankid:balance $balance
bankid:username $username
bankid:password $password
bankid:balance $balance
以上的設計為銀行帳戶的部分,
若要再加上交易行為紀錄,命名的部分就需要多加考慮,撈資料才好撈。
交易行為分為存款與提款,匯款的部分就是雙方存款提款的組合,這邊先設計存款提款就好。
若要再加上交易行為紀錄,命名的部分就需要多加考慮,撈資料才好撈。
交易行為分為存款與提款,匯款的部分就是雙方存款提款的組合,這邊先設計存款提款就好。
一開始一樣用bank_id來當作key,目的是為了查詢某個銀行的某幾筆交易紀錄,
例如某銀行所有交易紀錄指令就可以下 KEYS bank_id:trade_id*
KEYS用來查詢符合條件的KEY, '*'代表符合前面這段的全部值
結合起來意思就是是查詢以 帳戶:交易紀錄編號 為開頭的所有KEY。
例如某銀行所有交易紀錄指令就可以下 KEYS bank_id:trade_id*
KEYS用來查詢符合條件的KEY, '*'代表符合前面這段的全部值
結合起來意思就是是查詢以 帳戶:交易紀錄編號 為開頭的所有KEY。
先規劃架構如下,這邊雖然麻煩點不過為了以後下指令比較明白,
將KEY以欄位冒號值的形式描述,並在開頭帶上table name。
將KEY以欄位冒號值的形式描述,並在開頭帶上table name。
trade:bankid:$bankid:tradeid:$tradeid:behavior $deposit
trade:bankid:$bankid:tradeid:$tradeid:amount $amount
trade:bankid:$bankid:tradeid:$tradeid:date $date
...
這樣設計的問題在於,以交易紀錄作為最小的索引再去抓對應的行為,
這樣很不直觀,例如今天要取得交易金額,使用GET取值。
這樣很不直觀,例如今天要取得交易金額,使用GET取值。
GET trade:bankid:$bankid:tradeid:$tradeid:amount
執行上面的結果會得到對應的value $amount
問題是在處理邏輯的時候從
的KEY的名稱來看,根本看不出來這是存款還是匯款的紀錄,雖然這筆交易確實是存款沒錯,
所以有最好是把交易行為也納入key的命名之中,
例如
此時GET KEY可以直觀的解釋為要撈
某個銀行帳戶的
某筆交易紀錄的
交易行為是存款的
交易金額。
trade:bankid:$bankid:tradeid:$tradeid:amount
的KEY的名稱來看,根本看不出來這是存款還是匯款的紀錄,雖然這筆交易確實是存款沒錯,
所以有最好是把交易行為也納入key的命名之中,
例如
trade:bankid:$bankid:tradeid:$tradeid:behavior:$behavior:amount
,此時GET KEY可以直觀的解釋為要撈
某個銀行帳戶的
某筆交易紀錄的
交易行為是存款的
交易金額。
這時候又發現奇怪的地方,若我們是要查某銀行帳戶的所有存款紀錄
毫無疑問的bankid一定要放在key的第一位,
但接著是要查存款紀錄,所以就不應該擺tradeid,
因為照原本的寫法代表的是先查銀行在查這筆紀錄再去確認行為再去撈金額,
因此在確認交易行為之前,我們不知道他是不是存款,
代表我們需要全部檢查,並記錄相符的檢查結果,再去重新撈,非常沒效率。
毫無疑問的bankid一定要放在key的第一位,
但接著是要查存款紀錄,所以就不應該擺tradeid,
因為照原本的寫法代表的是先查銀行在查這筆紀錄再去確認行為再去撈金額,
因此在確認交易行為之前,我們不知道他是不是存款,
代表我們需要全部檢查,並記錄相符的檢查結果,再去重新撈,非常沒效率。
所以應該是要把常用的判斷往前移,
像是
這樣我們要查詢某帳戶的所有存款行為,
可以下
像是
trade:bankid:$bankid:behavior:$behavior:tradeid:$tradeid:amount
這樣我們要查詢某帳戶的所有存款行為,
可以下
KEYS trade:bankid:$bankid:behavior:$behavior*
例如下
就會列出
KEYS rade:bankid:123456:behavior:deposit*
就會列出
trade:bankid:123456:behavior:deposit:tradeid:456123:amount
trade:bankid:123456:behavior:deposit:tradeid:456123:date
...
trade:bankid:123456:behavior:deposit:tradeid:932458:amount
trade:bankid:123456:behavior:deposit:tradeid:75332:date
trade:bankid:123456:behavior:deposit:tradeid:433333amount
trade:bankid:123456:behavior:deposit:tradeid:4577892:date
...
現在查詢已經清楚多了,不過要取得這某筆交易ID的所有紀錄還是很麻煩,
假如按以上的作法,得到的會是所有存款紀錄的所有欄位KEY混再一起。
假如按以上的作法,得到的會是所有存款紀錄的所有欄位KEY混再一起。
所以這種很多欄位的將它改成hash看看,以 帳戶:行為:交易紀錄 命名作為KEY來儲存,格式如下:
KEY field value field value …
KEY field value field value …
trade:bankid:$bankid:behavior:$behavior:tradeid:$tradeid amount $amount date $date ...
可以使用HMSET key field value 的形式一次設定KEY與多個欄位值
並使用HGET key field 來取得key的特定欄位值
現在我們將tradeid也放入欄位中方便取得,
這樣一來再撈資料的時候只需要
就可以得到所有存款紀錄,
再去針對每一筆存款紀錄跑 HGET 得到特定欄位或 HGETALL 得到出所有欄位跟value的結果,
並將結果存成陣列就可以很好的在其他地方使用了。
並使用HGET key field 來取得key的特定欄位值
現在我們將tradeid也放入欄位中方便取得,
這樣一來再撈資料的時候只需要
KEYS trade:bankid:$bankid:behavior:$behavior*
就可以得到所有存款紀錄,
再去針對每一筆存款紀錄跑 HGET 得到特定欄位或 HGETALL 得到出所有欄位跟value的結果,
並將結果存成陣列就可以很好的在其他地方使用了。
不過上面都是踩雷的結果,
最後還是回到只用單一KEY存balance,
因為真正需要快取的是那些不斷變動的資料,也就是帳號目前金額。
其他資料雖然全部都存到redis雖然不是問題,
但$$要夠多,因為redis是直接in memory的。
最後還是回到只用單一KEY存balance,
因為真正需要快取的是那些不斷變動的資料,也就是帳號目前金額。
其他資料雖然全部都存到redis雖然不是問題,
但$$要夠多,因為redis是直接in memory的。
所以原本設計是同步寫入所有資料到MySQL與Redis,
要讀資料再去從redis撈,而不是從MySQL。
要讀資料再去從redis撈,而不是從MySQL。
但就有點失去將redis作為快取的目的,
會變動的只有balance所以應該只要在寫入所有資料到MySQL的同時,
只將balance另外寫入redis就好,
剩下的固定資料一樣從mysql撈,
查詢餘額時則是向redis撈,這樣就不需要再撈整筆紀錄出來再去撈餘額達到我們要的快取目的。
會變動的只有balance所以應該只要在寫入所有資料到MySQL的同時,
只將balance另外寫入redis就好,
剩下的固定資料一樣從mysql撈,
查詢餘額時則是向redis撈,這樣就不需要再撈整筆紀錄出來再去撈餘額達到我們要的快取目的。
REF:
http://yhhuang1966.blogspot.tw/2015/07/lua_14.html
http://blog.csdn.net/irean_lau/article/details/51395515
結構圖:
https://www.zhihu.com/question/36413559
https://github.com/liukelin/canal_mysql_nosql_sync
http://blog.csdn.net/irean_lau/article/details/51395515
結構圖:
https://www.zhihu.com/question/36413559
https://github.com/liukelin/canal_mysql_nosql_sync
浅谈Redis数据库的键值设计
http://blog.nosqlfan.com/html/3033.html
https://github.com/snc/SncRedisBundle/blob/master/Resources/doc/index.md
https://www.oschina.net/translate/mysql-to-redis-in-one-step
https://www.oschina.net/translate/mysql-to-redis-in-one-step
以下為不相關的記錄,真的應該去買本資料庫結構來啃R
...
3 75 $redis = $this->container->get('snc_redis.default');~
3 76 $redis->SET("bank:bankid:$registerID:username","$registerUsername");~
3 77 $redis->SET("bank:bankid:$registerID:paassword","$registerPassword");~
3 78 $redis->SET("bank:bankid:$registerID:balance",'0');~
...
127.0.0.1:6379> KEYS *
1) "bank:bankid:121:balance"
2) "bank:bankid:121:username"
3) "bank:bankid:121:paassword"
127.0.0.1:6379> get "bank:bankid:121:balance"
"0"
127.0.0.1:6379> get "bank:bankid:121:username"
"C8763_6"
127.0.0.1:6379> get "bank:bankid:121:paassword"
"0000"
127.0.0.1:6379> scan 0 MATCH * COUNT 1000
1) "0"
2) 1) "bank:bankid:121:paassword"
2) "bank:bankid:121:balance"
3) "bank:bankid:121:username"
使用KEY 儲存的問題
trade:bankid:1:behavior:Deposit:tradeid:40630:tradeDate"
trade:bankid:1:behavior:Deposit:tradeid:40630:tradeDate"
KEYS trade:bankid:1:behavior:Deposit:tradeid:40630*
會找到一堆0630的資料 要個別取直很麻煩
用LIST 就只會找到一筆0630 再把裡面資訊列出來比較方便
LPUSH
redis> LPUSH mylist "world"
(integer) 1
redis> LPUSH mylist "hello"
(integer) 2
redis> LRANGE mylist 0 -1
1) "hello"
2) "world"
LINDEX
redis> LPUSH mylist "World"
(integer) 1
redis> LPUSH mylist "Hello"
(integer) 2
redis> LINDEX mylist 0
"Hello"
redis> LINDEX mylist -1
"World"
redis> LINDEX mylist 3
(nil)
留言
張貼留言