當(dāng)前位置:首頁(yè) >  站長(zhǎng) >  網(wǎng)站運(yùn)營(yíng) >  正文

大型網(wǎng)站架構(gòu)系列之三 多對(duì)多關(guān)系的優(yōu)化設(shè)計(jì)

 2008-09-18 14:02  來(lái)源:   我來(lái)投稿 撤稿糾錯(cuò)

  域名預(yù)訂/競(jìng)價(jià),好“米”不錯(cuò)過(guò)

接上篇,大型網(wǎng)站架構(gòu)系列之二 底層架構(gòu)概論

上篇以用戶數(shù)據(jù)表為例介紹了基本的數(shù)據(jù)分割方案以及基本的配置方案。但是在2.0時(shí)代,這種簡(jiǎn)單的列表索引已經(jīng)遠(yuǎn)遠(yuǎn)實(shí)現(xiàn)起來(lái)是問(wèn)題的,多對(duì)多關(guān) 系將是最常見(jiàn)的關(guān)系?,F(xiàn)在我們針對(duì)web2.0數(shù)據(jù)中廣泛存在的多對(duì)多關(guān)系進(jìn)行闡述和具體行為判斷,比如一個(gè)很簡(jiǎn)單的例子,在2.0時(shí)代,好友功能是最常 被用到的,每個(gè)用戶會(huì)有很多的好友,同時(shí)也會(huì)是很多人的好友,那么這個(gè)數(shù)據(jù)量將會(huì)是用戶數(shù)的平方的級(jí)別。同樣,對(duì)于文章標(biāo)簽,每個(gè)文章可以有多個(gè)標(biāo)簽,而 每個(gè)標(biāo)簽又可以有多個(gè)文章,這又是一個(gè)幾何乘積,數(shù)據(jù)量又會(huì)是個(gè)天文數(shù)字。

傳統(tǒng)的處理方案有兩種,一種是通過(guò)SEARCH的方法來(lái)實(shí)現(xiàn),一種是通過(guò)另建一個(gè)索引表,存貯對(duì)應(yīng)的ID以進(jìn)行存貯。對(duì)于第一種方案,因?yàn)橐?及大量的LIKE查詢,性能不敢恭維,第二種的情況下,數(shù)據(jù)庫(kù)的行的數(shù)量也是驚人海量級(jí)別的,并且要跨表跨區(qū)查詢,還要維護(hù)數(shù)據(jù)的唯一性,數(shù)據(jù)處理過(guò)程相 當(dāng)?shù)膹?fù)雜性能也就不言而喻了。

文入正題,下面對(duì)數(shù)據(jù)多對(duì)多關(guān)系舉出來(lái)具體的解決方案,我們這里以標(biāo)簽和文章之間的多對(duì)多關(guān)系為例來(lái)講解,大家可以舉一反三的思考群組和用戶之間,相冊(cè)和被圈用戶之間等等復(fù)雜的多對(duì)多關(guān)系。

首先濾清一下流程,我們以傳統(tǒng)方案的第二種為例,在傳統(tǒng)的數(shù)據(jù)庫(kù)設(shè)計(jì)中我們是如下走的:當(dāng)一篇博文發(fā)布的時(shí)候并插入標(biāo)簽的時(shí)候一般是三步走(也 可以理解為四步,以為還要判斷標(biāo)簽是否存在的問(wèn)題),第一步插入文章數(shù)據(jù)庫(kù)并獲取文章的ID,第二步插入標(biāo)簽數(shù)據(jù)庫(kù)同時(shí)查詢標(biāo)簽是否存在,如果存在就取出 標(biāo)簽的ID,否則的話插入新標(biāo)簽并取出ID,第三部,將文章的ID和標(biāo)簽的ID插入索引表來(lái)建立關(guān)聯(lián)。如果這個(gè)時(shí)候在索引表上建立了索引的話就是災(zāi)難性 的,特別是在數(shù)據(jù)量大的情況下,盡管它可以有效的提高查詢速度,但是發(fā)布的速度可能就會(huì)讓人無(wú)法忍受了。

我們處理的方法也是三部曲,對(duì)多對(duì)多關(guān)系進(jìn)行進(jìn)一步的處理。

用標(biāo)簽的時(shí)候,我們用的最多的就是查詢標(biāo)簽下的文章和顯示文章的標(biāo)簽,所以我們實(shí)現(xiàn)這例就成了。

第一步,拋棄索引表。

對(duì)文章做冗余字段,加一個(gè)TAG列,我們可以講TAG的標(biāo)簽如下寫[TagID,TagName]| [TagID,TagName]| [TagID,TagName] 同樣 對(duì)于TAG表,我們做如下冗余加個(gè)Article字段,如下內(nèi)容[ArticleID,Title]| [ArticleID, Title]| [ArticleID, Title],在需要增加的時(shí)候我們只要APPEND一下就可以了,至于ARTICLE的結(jié)構(gòu)和TAG的結(jié)構(gòu)可以參考我上一篇文章的介紹。其實(shí)根據(jù)需要還 可以存貯更多。

有人會(huì)問(wèn),為什么要存貯TagName和ArticleTitle呢,其實(shí)是為了避免跨表查詢和INNERJOIN查詢來(lái)做的,In查詢和跨表查詢會(huì)造成全表遍歷,所以我們?cè)趫?zhí)行的時(shí)候In查詢是必須要找到一個(gè)有效的替代方法的。

第二部:異步加載。

在設(shè)計(jì)模式下我們常思考的是單件模式,我們采用另類的單件模式來(lái)處理,也就是把文章和標(biāo)簽之間的索引作為專門的進(jìn)程來(lái)做,異步的實(shí)現(xiàn)。

為了避免文章在發(fā)布的時(shí)候以為要檢查TAG表而造成的線程擁堵,我們需要采取延遲加載的方案來(lái)做。服務(wù)器應(yīng)該維護(hù)一個(gè)進(jìn)程專業(yè)的對(duì)標(biāo)簽和文章地段的查詢和索引,我們?cè)诎l(fā)布文章的時(shí)候應(yīng)該把標(biāo)簽同步這一塊托管給另外的一個(gè)程序進(jìn)行處理,并進(jìn)行索引。

第三部:標(biāo)簽緩存索引:

對(duì)于頻繁的判斷標(biāo)簽去或者熱門的標(biāo)簽我們還可以組織一套有效的索引,比如對(duì)于標(biāo)簽“瘋狂代碼”和”傲博知識(shí)庫(kù)”,我們用樹(shù)來(lái)把它表示出來(lái)。對(duì)于 瘋狂代碼我們索引一個(gè)瘋,其實(shí)用程序表達(dá)就是瘋狂代碼[0],同樣傲博知識(shí)庫(kù)就是傲博知識(shí)庫(kù)[0]。而在數(shù)組”瘋”中存貯以瘋開(kāi)頭的標(biāo)簽組,以”傲”的數(shù) 組中存貯以”傲”開(kāi)頭的標(biāo)簽。如果量更大的話還可以再做二級(jí)索引。

這涉及另外一個(gè)話題了就是分詞,上面是一個(gè)簡(jiǎn)單的分詞方案,大家在進(jìn)行GOOGLE搜索的時(shí)候應(yīng)該很輸入它的Suggest方法吧,就是這個(gè)道理。最終講標(biāo)簽有效的索引,并提取熱門的作為一個(gè)全局靜態(tài)變量,我們就可以繞過(guò)數(shù)據(jù)查詢這一關(guān),對(duì)第二部的單件模式又是一個(gè)進(jìn)化。

以上是對(duì)多對(duì)多關(guān)系的一個(gè)簡(jiǎn)單的架構(gòu)說(shuō)明,肯定有人會(huì)問(wèn),如果這樣做的話工作量不是太大了嗎,分詞處理什么的,對(duì)每個(gè)多對(duì)多關(guān)系進(jìn)行處理。

OK,咱們可以進(jìn)一步的把它來(lái)抽象化,我們用TableA 表示Article表,用TagbleT表示Tag表,我們可以講字段抽象化出來(lái),也就是一個(gè)ID,一個(gè)Tag的String 同理對(duì)于標(biāo)簽表也是如此。朋友們應(yīng)該可以理解我的意思了。

對(duì),就是做個(gè)代碼生成器把對(duì)應(yīng)的多對(duì)多關(guān)系給生成出來(lái),這個(gè)很好寫的,幾個(gè)Append就可以搞定。如果想更方便的處理,那么把這個(gè)東西做成單件的模式抽象化出來(lái),然后再違反一下原則,做成基類,其他關(guān)系繼承這個(gè)基類。。。。。剩下的應(yīng)該很簡(jiǎn)單了,具體實(shí)現(xiàn)大家思考吧。

請(qǐng)參照第二篇的文章進(jìn)行進(jìn)一步優(yōu)化設(shè)計(jì)來(lái)實(shí)現(xiàn)更高的負(fù)載性能

下章接著講述數(shù)據(jù)分割和散列方面的內(nèi)容

瘋狂代碼原創(chuàng)發(fā)布,同步發(fā)布于 和

轉(zhuǎn)載請(qǐng)注明出處

申請(qǐng)創(chuàng)業(yè)報(bào)道,分享創(chuàng)業(yè)好點(diǎn)子。點(diǎn)擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!

相關(guān)文章

熱門排行

信息推薦