Redis數(shù)據(jù)庫(kù)常見(jiàn)的鍵值設(shè)計(jì)有哪些-創(chuàng)新互聯(lián)

這篇文章將為大家詳細(xì)講解有關(guān)Redis數(shù)據(jù)庫(kù)常見(jiàn)的鍵值設(shè)計(jì)有哪些,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)安平,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢(xún)建站服務(wù):18980820575

用戶(hù)登錄系統(tǒng)

記錄用戶(hù)登錄信息的一個(gè)系統(tǒng),我們簡(jiǎn)化業(yè)務(wù)后只留下一張表。

關(guān)系型數(shù)據(jù)庫(kù)的設(shè)計(jì)

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表示用戶(hù)名,login_times表示該用戶(hù)的登錄次數(shù),每次用戶(hù)登錄后,login_times會(huì)自增,而last_login_time更新為當(dāng)前時(shí)間。

REDIS的設(shè)計(jì)

關(guān)系型數(shù)據(jù)轉(zhuǎn)化為KV數(shù)據(jù)庫(kù),我的方法如下:

key表名:主鍵值:列名

value列值

一般使用冒號(hào)做分割符,這是不成文的規(guī)矩。比如在php-adminforredis系統(tǒng)里,就是默認(rèn)以冒號(hào)分割,于是user:1user:2等key會(huì)分成一組。于是以上的關(guān)系數(shù)據(jù)轉(zhuǎn)化成kv數(shù)據(jù)后記錄如下:

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“

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

一般用戶(hù)是無(wú)法知道自己的id的,只知道自己的用戶(hù)名,所以還必須有一個(gè)從name到id的映射關(guān)系,這里的設(shè)計(jì)與上面的有所不同。

set"login:kenthompson:id"1

set"login:dennisritchie:id"2

set"login:JoeArmstrong:id"3

這樣每次用戶(hù)登錄的時(shí)候業(yè)務(wù)邏輯如下(python版),r是redis對(duì)象,name是已經(jīng)獲知的用戶(hù)名。

#獲得用戶(hù)的id

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

#自增用戶(hù)的登錄次數(shù)

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

#更新該用戶(hù)的最后登錄時(shí)間

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

如果需求僅僅是已知id,更新或者獲取某個(gè)用戶(hù)的最后登錄時(shí)間,登錄次數(shù),關(guān)系型和kv數(shù)據(jù)庫(kù)無(wú)啥區(qū)別。一個(gè)通過(guò)btreepk,一個(gè)通過(guò)hash,效果都很好。

假設(shè)有如下需求,查找最近登錄的N個(gè)用戶(hù)。開(kāi)發(fā)人員看看,還是比較簡(jiǎn)單的,一個(gè)sql搞定。

select*fromloginorderbylast_login_timedesclimitN

DBA了解需求后,考慮到以后表如果比較大,所以在last_login_time上建個(gè)索引。執(zhí)行計(jì)劃從索引leafblock的最右邊開(kāi)始訪(fǎng)問(wèn)N條記錄,再回表N次,效果很好。

有哪些常見(jiàn)Redis數(shù)據(jù)庫(kù)鍵值的設(shè)計(jì)

過(guò)了兩天,又來(lái)一個(gè)需求,需要知道登錄次數(shù)最多的人是誰(shuí)。同樣的關(guān)系型如何處理?DEV說(shuō)簡(jiǎn)單

select*fromloginorderbylogin_timesdesclimitN

DBA一看,又要在login_time上建立一個(gè)索引。有沒(méi)有覺(jué)得有點(diǎn)問(wèn)題呢,表上每個(gè)字段上都有素引。

關(guān)系型數(shù)據(jù)庫(kù)的數(shù)據(jù)存儲(chǔ)的的不靈活是問(wèn)題的源頭,數(shù)據(jù)僅有一種儲(chǔ)存方法,那就是按行排列的堆表。統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)意味著你必須使用索引來(lái)改變sql的訪(fǎng)問(wèn)路徑來(lái)快速訪(fǎng)問(wèn)某個(gè)列的,而訪(fǎng)問(wèn)路徑的增加又意味著你必須使用統(tǒng)計(jì)信息來(lái)輔助,于是一大堆的問(wèn)題就出現(xiàn)了。

沒(méi)有索引,沒(méi)有統(tǒng)計(jì)計(jì)劃,沒(méi)有執(zhí)行計(jì)劃,這就是kv數(shù)據(jù)庫(kù)。

redis里如何滿(mǎn)足以上的需求呢?對(duì)于求新的N條數(shù)據(jù)的需求,鏈表的后進(jìn)后出的特點(diǎn)非常適合。我們?cè)谏厦娴牡卿洿a之后添加一段代碼,維護(hù)一個(gè)登錄的鏈表,控制他的長(zhǎng)度,使得里面永遠(yuǎn)保存的是最近的N個(gè)登錄用戶(hù)。

#把當(dāng)前登錄人添加到鏈表里

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)

另外,求登錄次數(shù)最多的人,對(duì)于排序,積分榜這類(lèi)需求,sortedset非常的適合,我們把用戶(hù)和登錄次數(shù)統(tǒng)一存儲(chǔ)在一個(gè)sortedset里。

zaddlogin:login_times51

zaddlogin:login_times12

zaddlogin:login_times23

這樣假如某個(gè)用戶(hù)登錄,額外維護(hù)一個(gè)sortedset,代碼如此

#對(duì)該用戶(hù)的登錄次數(shù)自增1

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

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

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

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

TAG系統(tǒng)

tag在互聯(lián)網(wǎng)應(yīng)用里尤其多見(jiàn),如果以傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)來(lái)設(shè)計(jì)有點(diǎn)不倫不類(lèi)。我們以查找書(shū)的例子來(lái)看看redis在這方面的優(yōu)勢(shì)。

關(guān)系型數(shù)據(jù)庫(kù)的設(shè)計(jì)

兩張表,一張book的明細(xì),一張tag表,表示每本的tag,一本書(shū)存在多個(gè)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方面的書(shū)籍,如果以關(guān)系型數(shù)據(jù)庫(kù)會(huì)怎么處理?

selectb.name,b.authorfromtagt1,tagt2,bookb

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

tag表自關(guān)聯(lián)2次再與book關(guān)聯(lián),這個(gè)sql還是比較復(fù)雜的,如果要求即ruby,但不是web方面的書(shū)籍呢?

關(guān)系型數(shù)據(jù)其實(shí)并不太適合這些集合操作。

REDIS的設(shè)計(jì)

首先book的數(shù)據(jù)肯定要存儲(chǔ)的,和上面一樣。

setbook:1:name”TheRubyProgrammingLanguage”

Setbook:2:name”Rubyonrail”

Setbook:3:name”P(pán)rogrammingErlang”

setbook:1:author”MarkPilgrim”

Setbook:2:author”DavidFlanagan”

Setbook:3:author”JoeArmstrong”

tag表我們使用集合來(lái)存儲(chǔ)數(shù)據(jù),因?yàn)榧仙瞄L(zhǎng)求交集、并集

saddtag:ruby1

saddtag:ruby2

saddtag:web2

saddtag:erlang3

那么,即屬于ruby又屬于web的書(shū)?

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

即屬于ruby,但不屬于web的書(shū)?

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

屬于ruby和屬于web的書(shū)的合集?

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

簡(jiǎn)單到不行阿。

從以上2個(gè)例子可以看出在某些場(chǎng)景里,關(guān)系型數(shù)據(jù)庫(kù)是不太適合的,你可能能夠設(shè)計(jì)出滿(mǎn)足需求的系統(tǒng),但總是感覺(jué)的怪怪的,有種生搬硬套的感覺(jué)。

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

關(guān)于“Redis數(shù)據(jù)庫(kù)常見(jiàn)的鍵值設(shè)計(jì)有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

名稱(chēng)欄目:Redis數(shù)據(jù)庫(kù)常見(jiàn)的鍵值設(shè)計(jì)有哪些-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://muchs.cn/article20/pdgjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開(kāi)發(fā)、域名注冊(cè)手機(jī)網(wǎng)站建設(shè)、商城網(wǎng)站、網(wǎng)站維護(hù)靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開(kāi)發(fā)