1什么是NoSQL
大家有沒有聽說過“NoSQL”呢?近年,這個(gè)詞極受關(guān)注。。看到"NoSQL"這個(gè)詞,大家可能會(huì)誤以為是"No!SQL"的縮寫,并深感詫異:"SQL怎么會(huì)沒有必要了呢?"但實(shí)際上,它是"Not Only SQL"的縮寫。它的意義是:適用關(guān)系型數(shù)據(jù)庫的時(shí)候就使用關(guān)系型數(shù)據(jù)庫,不適用的時(shí)候也沒有必要非使用關(guān)系型數(shù)據(jù)庫不可,可以考慮使用更加合適的數(shù)據(jù)存儲(chǔ)。
為彌補(bǔ)關(guān)系型數(shù)據(jù)庫的不足,各種各樣的NoSQL數(shù)據(jù)庫應(yīng)運(yùn)而生。
2關(guān)系型數(shù)據(jù)庫的簡(jiǎn)史
1969年,埃德加·弗蘭克·科德(Edgar Frank Codd)發(fā)表了一篇?jiǎng)潟r(shí)代的論文,首次提出了關(guān)系數(shù)據(jù)模型的概念。但可惜的是,刊登論文的"IBM Research Report"只是IBM公司的內(nèi)部刊物,因此論文反響平平。1970年,他再次在刊物《Communication of the ACM》上發(fā)表了題為"A Relational Model of Data for Large Shared Databanks"(大型共享數(shù)據(jù)庫的關(guān)系模型)的論文,終于引起了大家的關(guān)注。
科德所提出的關(guān)系數(shù)據(jù)模型的概念成為了現(xiàn)今關(guān)系型數(shù)據(jù)庫的基礎(chǔ)。當(dāng)時(shí)的關(guān)系型數(shù)據(jù)庫由于硬件性能低劣、處理速度過慢而遲遲沒有得到實(shí)際應(yīng)用。但之后隨著硬件性能的提升,加之使用簡(jiǎn)單、性能優(yōu)越等優(yōu)點(diǎn),關(guān)系型數(shù)據(jù)庫得到了廣泛的應(yīng)用。
3數(shù)據(jù)庫的分類
數(shù)據(jù)庫根據(jù)不同的數(shù)據(jù)模型(數(shù)據(jù)的表現(xiàn)形式)主要分成階層型、網(wǎng)絡(luò)型和關(guān)系型3種。
3.1階層型數(shù)據(jù)庫
早期的數(shù)據(jù)庫稱為階層型數(shù)據(jù)庫,數(shù)據(jù)的關(guān)系都是以簡(jiǎn)單的樹形結(jié)構(gòu)來定義的。程序也通過樹形結(jié)構(gòu)對(duì)數(shù)據(jù)進(jìn)行訪問。這種結(jié)構(gòu),父記錄(上層的記錄)同時(shí)擁有多個(gè)子記錄(下層記錄),子記錄只有唯一的父記錄。正因?yàn)槿绱?,這種非常簡(jiǎn)單的構(gòu)造在碰到復(fù)雜數(shù)據(jù)的時(shí)候往往會(huì)造成數(shù)據(jù)的重復(fù)(同一數(shù)據(jù)在數(shù)據(jù)庫內(nèi)重復(fù)出現(xiàn)),出現(xiàn)數(shù)據(jù)冗余的問題。圖所示為階層型數(shù)據(jù)庫。

階層型數(shù)據(jù)庫把數(shù)據(jù)通過階層結(jié)構(gòu)的方式表現(xiàn)出來,雖然這樣的結(jié)構(gòu)有利于提高查詢效率,但與此相對(duì)應(yīng)的是,不理解數(shù)據(jù)結(jié)構(gòu)就無法進(jìn)行高效的查詢。當(dāng)然,在階層結(jié)構(gòu)發(fā)生變更的時(shí)候,程序也需要進(jìn)行相應(yīng)的變更。
3.2網(wǎng)絡(luò)型數(shù)據(jù)庫
前所述,階層型數(shù)據(jù)庫會(huì)帶來數(shù)據(jù)重復(fù)的問題。為了解決這個(gè)問題,就出現(xiàn)了網(wǎng)絡(luò)型數(shù)據(jù)庫。它擁有同階層型數(shù)據(jù)庫相近的數(shù)據(jù)結(jié)構(gòu),同時(shí)各種數(shù)據(jù)又如同網(wǎng)狀交織在一起,因此而得名。
階層型數(shù)據(jù)庫只能通過父子關(guān)系來表現(xiàn)數(shù)據(jù)之間的關(guān)系。針對(duì)這一不足,網(wǎng)絡(luò)型數(shù)據(jù)庫可以使子記錄同時(shí)擁有多個(gè)父記錄,從而解決了數(shù)據(jù)冗余的問題。下圖所示為網(wǎng)絡(luò)型數(shù)據(jù)庫。
但是,在網(wǎng)絡(luò)型數(shù)據(jù)庫中,數(shù)據(jù)間比較復(fù)雜的網(wǎng)絡(luò)關(guān)系使得數(shù)據(jù)結(jié)構(gòu)的更新變得比較困難。另外,與階層型數(shù)據(jù)庫一樣,網(wǎng)絡(luò)型數(shù)據(jù)庫對(duì)數(shù)據(jù)結(jié)構(gòu)有很強(qiáng)的依賴性,不理解數(shù)據(jù)結(jié)構(gòu)就無法進(jìn)行相應(yīng)的數(shù)據(jù)訪問。
3.3關(guān)系型數(shù)據(jù)庫
最后要向大家介紹的是以科德提出的關(guān)系數(shù)據(jù)模型為基礎(chǔ)的關(guān)系型數(shù)據(jù)庫。關(guān)系型數(shù)據(jù)庫把所有的數(shù)據(jù)都通過行和列的二元表現(xiàn)形式表示出來,給人更容易理解的直觀感受。網(wǎng)絡(luò)型數(shù)據(jù)庫存在著數(shù)據(jù)結(jié)構(gòu)變更困難的問題,而關(guān)系型數(shù)據(jù)庫可以使多條數(shù)據(jù)根據(jù)值來進(jìn)行關(guān)聯(lián),這樣就使數(shù)據(jù)可以獨(dú)立存在,使得數(shù)據(jù)結(jié)構(gòu)的變更變得簡(jiǎn)單易行。
對(duì)于階層型數(shù)據(jù)庫和網(wǎng)絡(luò)型數(shù)據(jù)庫,如果不理解相應(yīng)的數(shù)據(jù)結(jié)構(gòu),就無法對(duì)數(shù)據(jù)進(jìn)行讀取,它們對(duì)數(shù)據(jù)結(jié)構(gòu)的依賴性很強(qiáng)。因此,它們往往需要專業(yè)的工程師使用特定的計(jì)算機(jī)程序進(jìn)行操作處理。相反,關(guān)系型數(shù)據(jù)庫將作為操作對(duì)象的數(shù)據(jù)和操作方法(數(shù)據(jù)之間的關(guān)聯(lián))分離開來,消除了對(duì)數(shù)據(jù)結(jié)構(gòu)的依賴性,讓數(shù)據(jù)和程序的分離成為可能。這使得數(shù)據(jù)庫可以廣泛應(yīng)用于各個(gè)不同領(lǐng)域,進(jìn)一步擴(kuò)大了數(shù)據(jù)庫的應(yīng)用范圍。
4關(guān)系型數(shù)據(jù)庫的優(yōu)勢(shì)
4.1通用性及高性能
"關(guān)系型數(shù)據(jù)庫的性能絕對(duì)不低,它具有非常好的通用性和非常高的性能"。毫無疑問,對(duì)于絕大多數(shù)的應(yīng)用來說它都是最有效的解決方案。
4.2突出的優(yōu)勢(shì)
關(guān)系型數(shù)據(jù)庫作為應(yīng)用廣泛的通用型數(shù)據(jù)庫,它的突出優(yōu)勢(shì)主要有以下幾點(diǎn):
l保持?jǐn)?shù)據(jù)的一致性(事務(wù)處理)
l由于以標(biāo)準(zhǔn)化為前提,數(shù)據(jù)更新的開銷很小(相同的字段基本上都只有一處)
l可以進(jìn)行JOIN等復(fù)雜查詢
l存在很多實(shí)際成果和專業(yè)技術(shù)信息(成熟的技術(shù))。
這其中,能夠保持?jǐn)?shù)據(jù)的一致性是關(guān)系型數(shù)據(jù)庫的最大優(yōu)勢(shì)。在需要嚴(yán)格保證數(shù)據(jù)一致性和處理完整性的情況下,用關(guān)系型數(shù)據(jù)庫是肯定沒有錯(cuò)的。但是有些情況不需要JOIN,對(duì)上述關(guān)系型數(shù)據(jù)庫的優(yōu)點(diǎn)也沒有什么特別需要,這時(shí)似乎也就沒有必要拘泥于關(guān)系型數(shù)據(jù)庫了。
5關(guān)系型數(shù)據(jù)庫的不足
5.1不擅長(zhǎng)的處理
就像之前提到的那樣,關(guān)系型數(shù)據(jù)庫的性能非常高。但是它畢竟是一個(gè)通用型的數(shù)據(jù)庫,并不能完全適應(yīng)所有的用途。具體來說它并不擅長(zhǎng)以下處理:
l大量數(shù)據(jù)的寫入處理
l為有數(shù)據(jù)更新的表做索引或表結(jié)構(gòu)(schema)變更
l字段不固定時(shí)應(yīng)用
l對(duì)簡(jiǎn)單查詢需要快速返回結(jié)果的處理
下面逐一進(jìn)行詳細(xì)的說明。
5.2大量數(shù)據(jù)的寫入處理
在數(shù)據(jù)讀入方面,由復(fù)制產(chǎn)生的主從模式(數(shù)據(jù)的寫入由主數(shù)據(jù)庫負(fù)責(zé),數(shù)據(jù)的讀入由從數(shù)據(jù)庫負(fù)責(zé)),可以比較簡(jiǎn)單地通過增加從數(shù)據(jù)庫來實(shí)現(xiàn)規(guī)模化。但是,在數(shù)據(jù)的寫入方面卻完全沒有簡(jiǎn)單的方法來解決規(guī)?;瘑栴}①讀寫集中在一個(gè)數(shù)據(jù)庫上讓數(shù)據(jù)庫不堪重負(fù),大部分網(wǎng)站開始使用主從復(fù)制技術(shù)來實(shí)現(xiàn)讀寫分離,以提高讀寫性能和讀庫的可擴(kuò)展性。Mysql的master-slave模式成為了這個(gè)時(shí)候的網(wǎng)站標(biāo)配。--譯者注。例如,要想將數(shù)據(jù)的寫入規(guī)?;梢钥紤]把主數(shù)據(jù)庫從一臺(tái)增加到兩臺(tái),作為互相關(guān)聯(lián)復(fù)制的二元主數(shù)據(jù)庫來使用。確實(shí)這樣似乎可以把每臺(tái)主數(shù)據(jù)庫的負(fù)荷減少一半,但是更新處理會(huì)發(fā)生沖突(同樣的數(shù)據(jù)在兩臺(tái)服務(wù)器同時(shí)更新成其他值),可能會(huì)造成數(shù)據(jù)的不一致。為了避免這樣的問題,就需要把對(duì)每個(gè)表的請(qǐng)求分別分配給合適的主數(shù)據(jù)庫來處理,這就不那么簡(jiǎn)單了。下圖所示為兩臺(tái)主機(jī)問題和二元主數(shù)據(jù)庫問題的解決辦法。
另外也可以考慮把數(shù)據(jù)庫分割開來,分別放在不同的數(shù)據(jù)庫服務(wù)器上,比如將這個(gè)表放在這個(gè)數(shù)據(jù)庫服務(wù)器上,那個(gè)表放在那個(gè)數(shù)據(jù)庫服務(wù)器上。數(shù)據(jù)庫分割可以減少每臺(tái)數(shù)據(jù)庫服務(wù)器上的數(shù)據(jù)量,以便減少硬盤I/O(輸入/輸出)處理,實(shí)現(xiàn)內(nèi)存上的高速處理,效果非常顯著。但是,由于分別存儲(chǔ)在不同服務(wù)器上的表之間無法進(jìn)行JOIN處理,數(shù)據(jù)庫分割的時(shí)候就需要預(yù)先考慮這些問題。數(shù)據(jù)庫分割之后,如果一定要進(jìn)行JOIN處理,就必須要在程序中進(jìn)行關(guān)聯(lián),這是非常困難的。下圖所示為數(shù)據(jù)庫分割。
5.3為有數(shù)據(jù)更新的表做索引或表結(jié)構(gòu)(schema)變更
在使用關(guān)系型數(shù)據(jù)庫時(shí),為了加快查詢速度需要?jiǎng)?chuàng)建索引,為了增加必要的字段就一定需要改變表結(jié)構(gòu)。為了進(jìn)行這些處理,需要對(duì)表進(jìn)行共享鎖定,這期間數(shù)據(jù)變更(更新、插入、刪除等)是無法進(jìn)行的。如果需要進(jìn)行一些耗時(shí)操作(例如為數(shù)據(jù)量比較大的表創(chuàng)建索引或者是變更其表結(jié)構(gòu)),就需要特別注意:長(zhǎng)時(shí)間內(nèi)數(shù)據(jù)可能無法進(jìn)行更新。下表所示為共享鎖和排他鎖。
名稱 | 鎖的影響范圍 | 別名 |
共享鎖 | 其他連接可以對(duì)數(shù)據(jù)進(jìn)行讀取但是不能修改數(shù)據(jù) | 讀鎖 |
排它鎖 | 其他連接無法對(duì)數(shù)據(jù)進(jìn)行讀取和修改操作 | 寫鎖 |
5.4字段不固定時(shí)的應(yīng)用
如果字段不固定,利用關(guān)系型數(shù)據(jù)庫也是比較困難的。有人會(huì)說"需要的時(shí)候,加個(gè)字段就可以了",這樣的方法也不是不可以,但在實(shí)際運(yùn)用中每次都進(jìn)行反復(fù)的表結(jié)構(gòu)變更是非常痛苦的。你也可以預(yù)先設(shè)定大量的預(yù)備字段,但這樣的話,時(shí)間一長(zhǎng)很容易弄不清楚字段和數(shù)據(jù)的對(duì)應(yīng)狀態(tài)(即哪個(gè)字段保存哪些數(shù)據(jù)),所以并不推薦使用。下圖所示為使用預(yù)備字段的情況。
5.5對(duì)簡(jiǎn)單查詢需要快速返回結(jié)果的處理
最后還有一點(diǎn),這點(diǎn)似乎稱不上是缺點(diǎn),但不管怎樣,關(guān)系型數(shù)據(jù)庫并不擅長(zhǎng)對(duì)簡(jiǎn)單①這里所說的"簡(jiǎn)單"指的是沒有復(fù)雜的查詢條件,而不是用JOIN的意思。的查詢快速返回結(jié)果。因?yàn)殛P(guān)系型數(shù)據(jù)庫是使用專門的SQL語言進(jìn)行數(shù)據(jù)讀取的,它需要對(duì)SQL語言進(jìn)行解析,同時(shí)還有對(duì)表的鎖定和解鎖這樣的額外開銷。這里并不是說關(guān)系型數(shù)據(jù)庫的速度太慢,而只是想告訴大家若希望對(duì)簡(jiǎn)單查詢進(jìn)行高速處理,則沒有必要非用關(guān)系型數(shù)據(jù)庫不可。
在這種情況下,我想推薦大家使用NoSQL數(shù)據(jù)庫。但是像MySQL提供了利用HandlerSocket這樣的變通方法,也是可行的。雖然使用的是關(guān)系型數(shù)據(jù)庫MySQL,但并沒有利用SQL而是直接進(jìn)行數(shù)據(jù)訪問。這樣的方法是非??焖俚?。下圖所示為HandlerSocket的概要。
6NoSQL數(shù)據(jù)庫
上節(jié)介紹了關(guān)系型數(shù)據(jù)庫的不足之處。為了彌補(bǔ)這些不足(特別是最近幾年),NoSQL數(shù)據(jù)庫出現(xiàn)了。關(guān)系型數(shù)據(jù)庫應(yīng)用廣泛,能進(jìn)行事務(wù)處理和JOIN等復(fù)雜處理。相對(duì)地,NoSQL數(shù)據(jù)庫只應(yīng)用在特定領(lǐng)域,基本上不進(jìn)行復(fù)雜的處理,但它恰恰彌補(bǔ)了之前所列舉的關(guān)系型數(shù)據(jù)庫的不足之處。
6.1易于數(shù)據(jù)的分散
如前所述,關(guān)系型數(shù)據(jù)庫并不擅長(zhǎng)大量數(shù)據(jù)的寫入處理。原本關(guān)系型數(shù)據(jù)庫就是以JOIN為前提的,就是說,各個(gè)數(shù)據(jù)之間存在關(guān)聯(lián)是關(guān)系型數(shù)據(jù)庫得名的主要原因。為了進(jìn)行JOIN處理,關(guān)系型數(shù)據(jù)庫不得不把數(shù)據(jù)存儲(chǔ)在同一個(gè)服務(wù)器內(nèi),這不利于數(shù)據(jù)的分散。相反,NoSQL數(shù)據(jù)庫原本就不支持JOIN處理,各個(gè)數(shù)據(jù)都是獨(dú)立設(shè)計(jì)的,很容易把數(shù)據(jù)分散到多個(gè)服務(wù)器上。由于數(shù)據(jù)被分散到了多個(gè)服務(wù)器上,減少了每個(gè)服務(wù)器上的數(shù)據(jù)量,即使要進(jìn)行大量數(shù)據(jù)的寫入操作,處理起來也更加容易。同理,數(shù)據(jù)的讀入操作當(dāng)然也同樣容易。
6.2提升性能和增大規(guī)模
下面說一點(diǎn)題外話,如果想要使服務(wù)器能夠輕松地處理更大量的數(shù)據(jù),那么只有兩個(gè)選擇:一是提升性能,二是增大規(guī)模。下面我們來整理一下這兩者的不同。
首先,提升性能指的就是通過提升現(xiàn)行服務(wù)器自身的性能來提高處理能力。這是非常簡(jiǎn)單的方法,程序方面也不需要進(jìn)行變更,但需要一些費(fèi)用。若要購買性能翻倍的服務(wù)器,需要花費(fèi)的資金往往不只是原來的2倍,可能需要多達(dá)5~10倍。這種方法雖然簡(jiǎn)單,但是成本較高。下圖所示為提升性能的費(fèi)用與性能曲線。
另一方面,增大規(guī)模指的是使用多臺(tái)廉價(jià)的服務(wù)器來提高處理能力。它需要對(duì)程序進(jìn)行變更,但由于使用廉價(jià)的服務(wù)器,可以控制成本。另外,以后只要依葫蘆畫瓢增加廉價(jià)服務(wù)器的數(shù)量就可以了。下圖所示為提升性能和增大規(guī)模。
6.3不對(duì)大量數(shù)據(jù)進(jìn)行處理的話就沒有使用的必要嗎?
NoSQL數(shù)據(jù)庫基本上來說為了"使大量數(shù)據(jù)的寫入處理更加容易(讓增加服務(wù)器數(shù)量更容易)"而設(shè)計(jì)的。但如果不是對(duì)大量數(shù)據(jù)進(jìn)行操作的話,NoSQL數(shù)據(jù)庫的應(yīng)用就沒有意義嗎?
答案是否定的。的確,它在處理大量數(shù)據(jù)方面很有優(yōu)勢(shì)。但實(shí)際上NoSQL數(shù)據(jù)庫還有各種各樣的特點(diǎn),如果能夠恰當(dāng)?shù)乩眠@些特點(diǎn),它就會(huì)非常有用。具體的例子將會(huì)在第2章和第3章進(jìn)行介紹,這些用途將會(huì)讓你感受到利用NoSQL的好處。
l希望順暢地對(duì)數(shù)據(jù)進(jìn)行緩存(Cache)處理
l希望對(duì)數(shù)組類型的數(shù)據(jù)進(jìn)行高速處理
l希望進(jìn)行全部保存
6.4多樣的NoSQL數(shù)據(jù)庫
NoSQL數(shù)據(jù)庫存在著"鍵值存儲(chǔ)"、"文檔型數(shù)據(jù)庫"、"列存儲(chǔ)數(shù)據(jù)庫"等各種各樣的種類,每種數(shù)據(jù)庫又包含各自的特點(diǎn)。
愛華網(wǎng)



