數(shù)據(jù)模型和查詢語(yǔ)言 -- 關(guān)系模型與文檔模型(一)

在今天,最著名的數(shù)據(jù)模型莫過于SQL了吧。這是一個(gè)Codd在1970年提出的關(guān)系模型:數(shù)據(jù)被組織成關(guān)系(稱為SQL中的表),其中每個(gè)關(guān)系都是無(wú)序的元組集合(SQL中的行)。

關(guān)系模型是一個(gè)理論上的設(shè)想,在當(dāng)時(shí)很多人都懷疑它是否能有效地實(shí)施。然而,到上世紀(jì)80年代中期,關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)和SQL已經(jīng)成為大多數(shù)需要使用某種常規(guī)結(jié)構(gòu)來(lái)存儲(chǔ)和查詢數(shù)據(jù)的人的首選工具,關(guān)系數(shù)據(jù)庫(kù)的主導(dǎo)地位也持續(xù)了25年之久。

關(guān)系數(shù)據(jù)庫(kù)的根源在于業(yè)務(wù)數(shù)據(jù)處理,在20世紀(jì)60年代和70年代這些其實(shí)是在大型計(jì)算機(jī)上執(zhí)行的。而從今天的角度來(lái)看,用例看起來(lái)也十分普通:典型的事務(wù)處理(進(jìn)入銷售或銀行事務(wù)、航空公司預(yù)訂、倉(cāng)庫(kù)中的庫(kù)存)和批處理(客戶發(fā)票、工資、報(bào)表)。當(dāng)時(shí)的其他數(shù)據(jù)庫(kù)還在迫使應(yīng)用程序開發(fā)人員考慮數(shù)據(jù)庫(kù)中數(shù)據(jù)的內(nèi)部表示,而關(guān)系模型的目標(biāo)卻是在一個(gè)更干凈的接口后面隱藏實(shí)現(xiàn)細(xì)節(jié)。

多年來(lái),人們都在比較不同的數(shù)據(jù)存儲(chǔ)和查詢的方法。比如,在20世紀(jì)70年代和80年代早期,網(wǎng)絡(luò)模型和層次模型是主要的替代方案,但是關(guān)系模型開始主導(dǎo)它們。在20世紀(jì)80年代末和90年代初,對(duì)象數(shù)據(jù)庫(kù)再次出現(xiàn)。而XML數(shù)據(jù)庫(kù)出現(xiàn)在21世紀(jì)初,但也只看到了特定的應(yīng)用。關(guān)系模型的每個(gè)競(jìng)爭(zhēng)對(duì)手都在其時(shí)代產(chǎn)生了大量的炒作,但從未持續(xù)過2次。

隨著計(jì)算機(jī)變得更加強(qiáng)大和網(wǎng)絡(luò)化,它們開始被用于日益多樣化的用途。值得注意的是,關(guān)系數(shù)據(jù)庫(kù)在最初的業(yè)務(wù)數(shù)據(jù)處理范圍之外,開始被廣泛應(yīng)用于各種用例。今天在web上看到的大部分內(nèi)容仍然由關(guān)系數(shù)據(jù)庫(kù)驅(qū)動(dòng),比如在線發(fā)布、討論、社交網(wǎng)絡(luò)、電子商務(wù)、游戲、SAAS應(yīng)用程序,甚至更多。

NOSQL的誕生

而現(xiàn)在,NoSQL是顛覆關(guān)系模式主導(dǎo)地位的最新嘗試?!癗oSQL”這個(gè)名字很不幸,因?yàn)樗鼘?shí)際上并不指代任何一種特定的技術(shù)——它最初只是作為一個(gè)吸引人的Twitter標(biāo)簽,用在2009年的一場(chǎng)關(guān)于開源分布式非關(guān)系型數(shù)據(jù)庫(kù)的meetup。然而,這個(gè)術(shù)語(yǔ)引起了很多人的關(guān)注,并迅速在網(wǎng)絡(luò)創(chuàng)業(yè)社區(qū)和其他地方傳播開來(lái)。現(xiàn)在,許多有趣的數(shù)據(jù)庫(kù)系統(tǒng)都與nosql關(guān)聯(lián)在一起,而且它還被重新解釋為不僅僅是SQL。

采用NoSQL數(shù)據(jù)庫(kù)的背后有幾個(gè)驅(qū)動(dòng)因素,主要包括:

????1.大家需要一個(gè)相比于關(guān)系數(shù)據(jù)庫(kù)來(lái)說(shuō),具有更大的可伸縮性,包括非常大的數(shù)據(jù)集或非常高的寫入吞吐量的系統(tǒng)。

????2.相比于商業(yè)數(shù)據(jù)庫(kù)產(chǎn)品,人們當(dāng)然更偏愛于免費(fèi)和開源軟件

????3.一些特殊的查詢操作,這是關(guān)系模型沒有很好支持的

????4.對(duì)關(guān)系模型限制性的失望,以及對(duì)更動(dòng)態(tài)、更富表現(xiàn)力的數(shù)據(jù)模型的渴望

不同的應(yīng)用程序有不同的需求,對(duì)于一個(gè)用例來(lái)說(shuō),最好的技術(shù)選擇可能與另一個(gè)用例的最佳選擇是不同的。因此,在可預(yù)見的將來(lái),關(guān)系數(shù)據(jù)庫(kù)將繼續(xù)與各種非關(guān)系型數(shù)據(jù)存儲(chǔ)一起使用。

對(duì)象-關(guān)系不匹配

在當(dāng)今,大多數(shù)應(yīng)用程序開發(fā)都是用面向?qū)ο蟮木幊陶Z(yǔ)言完成的,這導(dǎo)致了對(duì)SQL數(shù)據(jù)模型的常見批評(píng):如果數(shù)據(jù)存儲(chǔ)在關(guān)系表中,應(yīng)用程序代碼中的對(duì)象和表、行和列的數(shù)據(jù)庫(kù)模型之間需要一個(gè)笨拙的轉(zhuǎn)換層。模型之間的脫節(jié)有時(shí)被稱為阻抗失配。

像Hibernate這樣的對(duì)象-關(guān)系映射(ORM)框架減少了這個(gè)翻譯層所需的樣板代碼的數(shù)量,但是它們不能完全隱藏這兩個(gè)模型之間的差異。

例如,圖2-1演示了如何在關(guān)系模式中表達(dá)簡(jiǎn)歷(LinkedIn個(gè)人資料)。整個(gè)概要文件可以通過唯一標(biāo)識(shí)符userid來(lái)標(biāo)識(shí)。像firstname和lastname這樣的字段在每個(gè)用戶中出現(xiàn)一次,因此它們可以被建模為用戶表中的列。然而,大多數(shù)人的職業(yè)生涯(職位)都不止一份工作,而且人們的受教育年限和接觸信息的數(shù)量也各不相同。由此可見,這是一個(gè)一對(duì)多的關(guān)系,我們也可以用不同的方式表示:

? ? 1.在傳統(tǒng)SQL模型中(SQL1999),最常見的表達(dá)方式是將位置、教育、和聯(lián)系信息存在單獨(dú)的表中,然后跟用戶表建立外鍵引用,如圖2-1所示。

? ? 2.后來(lái)的SQL標(biāo)準(zhǔn)版本增加了對(duì)結(jié)構(gòu)化數(shù)據(jù)類型和XML數(shù)據(jù)的支持;這使得多值數(shù)據(jù)可以被存儲(chǔ)在一行中,并支持在這些文檔中查詢和索引。這些特性在Oracle、IBM DB2、SQL Server和PostgreSQL中都得到了不同程度的支持。JSON數(shù)據(jù)類型也受到幾個(gè)數(shù)據(jù)庫(kù)的支持,包括IBM DB2、MySQL和PostgreSQL。

? ? 3.第三種選擇是將工作、教育和聯(lián)系信息轉(zhuǎn)化成JSON或XML文檔,將其存儲(chǔ)在數(shù)據(jù)庫(kù)的文本列中,并讓應(yīng)用程序解釋其結(jié)構(gòu)和內(nèi)容。在這種設(shè)置中,通常不能使用數(shù)據(jù)庫(kù)直接查詢列內(nèi)的值。


圖2-1--使用關(guān)系模式表示一個(gè)LinkedIn個(gè)人資料。

對(duì)于像簡(jiǎn)歷這樣的數(shù)據(jù)結(jié)構(gòu)來(lái)說(shuō),它是一個(gè)自成體系的文檔,所以用JSON表示非常合適:參見例2-1。JSON的表達(dá)比XML要簡(jiǎn)單得多。面向文檔的數(shù)據(jù)庫(kù),如MongoDB、RethinkDB、CouchDB和Espresso,都支持這種數(shù)據(jù)模型。

例2-1,將LinkedIn個(gè)人資料用一個(gè)JSON表示:

{ "user_id": 251, "first_name": "Bill", "last_name": "Gates", "summary": "Co-chair of the Bill & Melinda Gates... Active blogger.", "region_id": "us:91", "industry_id": 131, "photo_url": "/p/7/000/253/05b/308dd6e.jpg", "positions": [ {"job_title": "Co-chair", "organization": "Bill & Melinda Gates Foundation"}, {"job_title": "Co-founder, Chairman", "organization": "Microsoft"} ], "education": [ {"school_name": "Harvard University", "start": 1973, "end": 1975}, {"school_name": "Lakeside School, Seattle", "start": null, "end": null} ], "contact_info": { "blog": "http://thegatesnotes.com", "twitter": "http://twitter.com/BillGates" }}

一些開發(fā)人員認(rèn)為JSON模型減少了應(yīng)用程序代碼和存儲(chǔ)層之間的阻抗失配。然而,正如我們將在第4章中看到的,JSON作為一種數(shù)據(jù)編碼格式也存在問題。缺乏schema通常被認(rèn)為是一種優(yōu)勢(shì),我們將在后續(xù)“文檔模型的模式靈活性”中討論這一點(diǎn)。

與圖2-1中的多表模式相比,JSON很明顯更加適合。如果您想要在關(guān)系示例中獲取profile,您需要執(zhí)行多條查詢(通過userid查詢每個(gè)表),或者在users表及其下屬表之間的做join。在JSON表示中,所有相關(guān)的信息都在一個(gè)地方,一個(gè)查詢就足夠了。

從用戶profile到用戶的位置、教育歷史和聯(lián)系信息的一對(duì)多關(guān)系,我們可以看出這是數(shù)據(jù)中的樹結(jié)構(gòu),而JSON能夠顯示的表達(dá)此樹結(jié)構(gòu)(參見圖2-2)。


圖2-2-- 一對(duì)多關(guān)系形成的一個(gè)樹形結(jié)構(gòu)

多對(duì)一和多對(duì)多關(guān)系

在前一節(jié)中,以2-1為例,區(qū)域id和行業(yè)id被作為id,而不是純文本字符串“大西雅圖地區(qū)”和“慈善”。為什么?

如果用戶界面有用于輸入?yún)^(qū)域和行業(yè)字段的文本框,那么將它們存儲(chǔ)為純文本字符串是有意義的。但是,擁有一個(gè)標(biāo)準(zhǔn)化的地理區(qū)域和行業(yè)列表,并讓用戶從下拉列表或自動(dòng)完成列表中進(jìn)行選擇是有一定的優(yōu)勢(shì)的,具體如下:

? ? 1.一致的風(fēng)格和拼寫

? ? 2.避免模棱兩可(例如,如果有幾個(gè)同名的城市)

? ? 3.易于更新——名稱只存儲(chǔ)在一個(gè)地方,因此,如果需要更改的話,它很容易進(jìn)行更新(例如,由于政治事件而更改城市名稱)。

????4.本地化支持——當(dāng)站點(diǎn)被翻譯成其他語(yǔ)言時(shí),標(biāo)準(zhǔn)化的列表可以本地化,因此區(qū)域和行業(yè)可以瀏覽者的本地語(yǔ)言來(lái)顯示。

? ? 5.更好的搜索。

是否存儲(chǔ)ID或文本字符串是一個(gè)關(guān)于重復(fù)的問題。當(dāng)您使用一個(gè)ID時(shí),對(duì)人類有意義的信息(例如慈善這個(gè)詞)只存儲(chǔ)在一個(gè)地方,并且所有引用它的信息都使用一個(gè)ID(它只在數(shù)據(jù)庫(kù)中有意義)。當(dāng)您直接存儲(chǔ)文本時(shí),您將在使用它的每條記錄中復(fù)制有意義的信息。

使用ID的優(yōu)點(diǎn)是,由于它對(duì)人沒有意義,所以它永遠(yuǎn)不需要改變:ID可以保持不變,即使它標(biāo)識(shí)的信息發(fā)生了變化。任何對(duì)人類有意義的事情都需要在將來(lái)的某個(gè)時(shí)候改變——如果這些信息是重復(fù)的,那么所有多余的副本都需要更新。這就會(huì)導(dǎo)致寫管理費(fèi)用,并存在不一致的風(fēng)險(xiǎn)(一些信息的副本會(huì)被更新,而其他的則不會(huì))。消除這種重復(fù)是數(shù)據(jù)庫(kù)中標(biāo)準(zhǔn)化背后的關(guān)鍵思想。

不幸的是,規(guī)范化這種數(shù)據(jù)需要多對(duì)一關(guān)系(許多人生活在一個(gè)特定的區(qū)域,許多人在一個(gè)特定的行業(yè)工作),這與文檔模型不太匹配。在關(guān)系型數(shù)據(jù)庫(kù)中,用ID引用其他表中的行是很正常的,因?yàn)閖oin很容易。在文檔數(shù)據(jù)庫(kù)中,通常不需要對(duì)一對(duì)多的樹結(jié)構(gòu)進(jìn)行join,而且對(duì)join的支持常常是弱的。

如果數(shù)據(jù)庫(kù)本身不支持join,那么您必須通過對(duì)數(shù)據(jù)庫(kù)進(jìn)行多次查詢來(lái)模擬應(yīng)用程序代碼中的join。(在這種情況下,區(qū)域和行業(yè)的列表可能很小,而且變化很慢,因此應(yīng)用程序可以簡(jiǎn)單地將它們保存在內(nèi)存中。但是,創(chuàng)建join的工作從數(shù)據(jù)庫(kù)轉(zhuǎn)移到應(yīng)用程序代碼。)

此外,即使應(yīng)用程序的初始版本很適合 join-free的文檔模型,數(shù)據(jù)也會(huì)隨著特性被添加到應(yīng)用程序中而變得更加相互關(guān)聯(lián)。例如,考慮一下我們可以對(duì)簡(jiǎn)歷示例進(jìn)行一些更改:

組織和學(xué)校作為實(shí)體

在前面的描述中,組織(用戶工作的公司)和學(xué)校名稱(他們學(xué)習(xí)的地方)只是字符串。也許它們應(yīng)該是對(duì)實(shí)體的引用?然后,每個(gè)組織、學(xué)?;虼髮W(xué)都可以擁有自己的網(wǎng)頁(yè)(帶有徽標(biāo)、新聞提要等);每個(gè)簡(jiǎn)歷都可以鏈接到它提到的組織和學(xué)校,并包含他們的標(biāo)志和其他信息(見圖2-3,來(lái)自LinkedIn的一個(gè)例子)。

建議

假設(shè)您想要添加一個(gè)新特性:一個(gè)用戶可以為另一個(gè)用戶寫推薦信。這些建議在被推薦的用戶的簡(jiǎn)歷上顯示,并附上推薦用戶的姓名和照片。如果推薦者更新他們的照片,他們所寫的任何推薦都需要反映新照片。因此,這些建議應(yīng)該有一個(gè)針對(duì)作者的個(gè)人資料的引用。


圖2-3--公司名稱不只是一個(gè)字符串,而是一個(gè)公司實(shí)體的鏈接? ?

圖2-4說(shuō)明了這些新特性為什么需要多對(duì)多關(guān)系。每個(gè)點(diǎn)狀矩形中的數(shù)據(jù)可以被分組到一個(gè)文檔中,但是對(duì)組織、學(xué)校和其他用戶的引用需要被表示為引用,并且在查詢時(shí)需要join。


圖2 - 4--多對(duì)多關(guān)系的擴(kuò)展簡(jiǎn)歷??
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容