久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Redis數據庫常見的鍵值設計有哪些

144次閱讀
沒有評論

共計 4238 個字符,預計需要花費 11 分鐘才能閱讀完成。

這篇文章將為大家詳細講解有關 Redis 數據庫常見的鍵值設計有哪些,丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

用戶登錄系統

記錄用戶登錄信息的一個系統,我們簡化業務后只留下一張表。

關系型數據庫的設計

mysql select*fromlogin;

+———+—————-+————-+———————+

|user_id|name|login_times|last_login_time|

+———+—————-+————-+———————+

|1|kenthompson|5|2011-01-0100:00:00|

|2|dennisritchie|1|2011-02-0100:00:00|

|3|JoeArmstrong|2|2011-03-0100:00:00|

+———+—————-+————-+———————+

user_id 表的主鍵,name 表示用戶名,login_times 表示該用戶的登錄次數,每次用戶登錄后,login_times 會自增,而 last_login_time 更新為當前時間。

REDIS 的設計

關系型數據轉化為 KV 數據庫,我的方法如下:

key 表名:主鍵值:列名

value 列值

一般使用冒號做分割符,這是不成文的規矩。比如在 php-adminforredis 系統里,就是默認以冒號分割,于是 user:1user:2 等 key 會分成一組。于是以上的關系數據轉化成 kv 數據后記錄如下:

Setlogin:1:login_times5

Setlogin:2:login_times1

Setlogin:3:login_times2

Setlogin:1:last_login_time2011-1-1

Setlogin:2:last_login_time2011-2-1

Setlogin:3:last_login_time2011-3-1

setlogin:1:name”kenthompson“

setlogin:2:name“dennisritchie”

setlogin:3:name”JoeArmstrong“

這樣在已知主鍵的情況下,通過 get、set 就可以獲得或者修改用戶的登錄次數和最后登錄時間和姓名。

一般用戶是無法知道自己的 id 的,只知道自己的用戶名,所以還必須有一個從 name 到 id 的映射關系,這里的設計與上面的有所不同。

set login:kenthompson:id 1

set login:dennisritchie:id 2

set login:JoeArmstrong:id 3

這樣每次用戶登錄的時候業務邏輯如下 (python 版),r 是 redis 對象,name 是已經獲知的用戶名。

#獲得用戶的 id

uid=r.get(login:%s:id %name)

#自增用戶的登錄次數

ret=r.incr(login:%s:login_times %uid)

#更新該用戶的最后登錄時間

ret=r.set(login:%s:last_login_time %uid,datetime.datetime.now())

如果需求僅僅是已知 id,更新或者獲取某個用戶的最后登錄時間,登錄次數,關系型和 kv 數據庫無啥區別。一個通過 btreepk,一個通過 hash,效果都很好。

假設有如下需求,查找最近登錄的 N 個用戶。開發人員看看,還是比較簡單的,一個 sql 搞定。

select*fromloginorderbylast_login_timedesclimitN

DBA 了解需求后,考慮到以后表如果比較大,所以在 last_login_time 上建個索引。執行計劃從索引 leafblock 的最右邊開始訪問 N 條記錄,再回表 N 次,效果很好。

有哪些常見 Redis 數據庫鍵值的設計

過了兩天,又來一個需求,需要知道登錄次數最多的人是誰。同樣的關系型如何處理?DEV 說簡單

select*fromloginorderbylogin_timesdesclimitN

DBA 一看,又要在 login_time 上建立一個索引。有沒有覺得有點問題呢,表上每個字段上都有素引。

關系型數據庫的數據存儲的的不靈活是問題的源頭,數據僅有一種儲存方法,那就是按行排列的堆表。統一的數據結構意味著你必須使用索引來改變 sql 的訪問路徑來快速訪問某個列的,而訪問路徑的增加又意味著你必須使用統計信息來輔助,于是一大堆的問題就出現了。

沒有索引,沒有統計計劃,沒有執行計劃,這就是 kv 數據庫。

redis 里如何滿足以上的需求呢? 對于求最新的 N 條數據的需求,鏈表的后進后出的特點非常適合。我們在上面的登錄代碼之后添加一段代碼,維護一個登錄的鏈表,控制他的長度,使得里面永遠保存的是最近的 N 個登錄用戶。

#把當前登錄人添加到鏈表里

ret=r.lpush(login:last_login_times ,uid)

#保持鏈表只有 N 位

ret=redis.ltrim(login:last_login_times ,0,N-1)

這樣需要獲得最新登錄人的 id,如下的代碼即可

last_login_list=r.lrange(login:last_login_times ,0,N-1)

另外,求登錄次數最多的人,對于排序,積分榜這類需求,sortedset 非常的適合,我們把用戶和登錄次數統一存儲在一個 sortedset 里。

zaddlogin:login_times51

zaddlogin:login_times12

zaddlogin:login_times23

這樣假如某個用戶登錄,額外維護一個 sortedset,代碼如此

#對該用戶的登錄次數自增 1

ret=r.zincrby(login:login_times ,1,uid)

那么如何獲得登錄次數最多的用戶呢,逆序排列取的排名第 N 的用戶即可

ret=r.zrevrange(login:login_times ,0,N-1)

可以看出,DEV 需要添加 2 行代碼,而 DBA 不需要考慮索引什么的。

TAG 系統

tag 在互聯網應用里尤其多見,如果以傳統的關系型數據庫來設計有點不倫不類。我們以查找書的例子來看看 redis 在這方面的優勢。

關系型數據庫的設計

兩張表,一張 book 的明細,一張 tag 表,表示每本的 tag,一本書存在多個 tag。

mysql select*frombook;

+——+——————————-+—————-+

|id|name|author|

+——+——————————-+—————-+

|1|TheRubyProgrammingLanguage|MarkPilgrim|

|1|Rubyonrail|DavidFlanagan|

|1|ProgrammingErlang|JoeArmstrong|

+——+——————————-+—————-+

mysql select*fromtag;

+———+———+

|tagname|book_id|

+———+———+

|ruby|1|

|ruby|2|

|web|2|

|erlang|3|

+———+———+

假如有如此需求,查找即是 ruby 又是 web 方面的書籍,如果以關系型數據庫會怎么處理?

selectb.name,b.authorfromtagt1,tagt2,bookb

wheret1.tagname= web andt2.tagname= ruby andt1.book_id=t2.book_idandb.id=t1.book_id

tag 表自關聯 2 次再與 book 關聯,這個 sql 還是比較復雜的,如果要求即 ruby,但不是 web 方面的書籍呢?

關系型數據其實并不太適合這些集合操作。

REDIS 的設計

首先 book 的數據肯定要存儲的,和上面一樣。

setbook:1:name”TheRubyProgrammingLanguage”

Setbook:2:name”Rubyonrail”

Setbook:3:name”ProgrammingErlang”

setbook:1:author”MarkPilgrim”

Setbook:2:author”DavidFlanagan”

Setbook:3:author”JoeArmstrong”

tag 表我們使用集合來存儲數據,因為集合擅長求交集、并集

saddtag:ruby1

saddtag:ruby2

saddtag:web2

saddtag:erlang3

那么,即屬于 ruby 又屬于 web 的書?

inter_list=redis.sinter(tag.web , tag:ruby)

即屬于 ruby,但不屬于 web 的書?

inter_list=redis.sdiff(tag.ruby , tag:web)

屬于 ruby 和屬于 web 的書的合集?

inter_list=redis.sunion(tag.ruby , tag:web)

簡單到不行阿。

從以上 2 個例子可以看出在某些場景里,關系型數據庫是不太適合的,你可能能夠設計出滿足需求的系統,但總是感覺的怪怪的,有種生搬硬套的感覺。

尤其登錄系統這個例子,頻繁的為業務建立索引。放在一個復雜的系統里,ddl(創建索引) 有可能改變執行計劃。導致其它的 sql 采用不同的執行計劃,業務復雜的老系統,這個問題是很難預估的,sql 千奇百怪。要求 DBA 對這個系統里所有的 sql 都了解,這點太難了。這個問題在 oracle 里尤其嚴重,每個 DBA 估計都碰到過。對于 MySQL 這類系統,ddl 又不方便 (雖然現在有 onlineddl 的方法)。碰到大表,DBA 凌晨爬起來在業務低峰期操作,這事我沒少干過。而這種需求放到 redis 里就很好處理,DBA 僅僅對容量進行預估即可。

關于“Redis 數據庫常見的鍵值設計有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-15發表,共計4238字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 巴东县| 江陵县| 甘肃省| 盐亭县| 郸城县| 栖霞市| 什邡市| 兰州市| 博罗县| 邹平县| 达孜县| 鄄城县| 普陀区| 册亨县| 常熟市| 巩留县| 九龙坡区| 土默特左旗| 黎城县| 监利县| 营山县| 环江| 丰台区| 石狮市| 内乡县| 隆昌县| 合山市| 茂名市| 浏阳市| 鄂州市| 新密市| 涡阳县| 通许县| 鹤岗市| 邯郸市| 金昌市| 凤台县| 嘉义县| 临澧县| 屏南县| 鹤壁市|