在前一篇文章中我們主要的討論了SQL與NoSQL數(shù)據(jù)庫之間的主要的差別腐宋。接下來紊服,我們將會利用上一篇中的知識來確定在特定的場景中如何確定比較好的選擇。
首先我們先來總結(jié)一下:
SQL數(shù)據(jù)庫:
- 使用表存儲相關(guān)的數(shù)據(jù)
- 在使用表之前需要先定義標(biāo)的模式
- 鼓勵使用規(guī)范化來減少數(shù)據(jù)的冗余
- 支持使用JION操作胸竞,使用一條SQL語句從多張表中取出相關(guān)的數(shù)據(jù)
- 需要滿足數(shù)據(jù)完整性約束規(guī)則
- 使用事務(wù)來保證數(shù)據(jù)的一致性
- 能夠大規(guī)模的使用
- 使用強(qiáng)大的SQL語言進(jìn)行查詢操作
- 提供大量的支持欺嗤,專業(yè)技能和輔助工具
NoSQL數(shù)據(jù)庫:
- 使用類JOSN格式的文檔來存儲鍵值對信息
- 存儲數(shù)據(jù)不需要特定的模式
- 使用非規(guī)范化的標(biāo)準(zhǔn)存儲信息,以保證一個文檔中包含一個條目的所有信息
- 不需要使用JION操作
- 允許數(shù)據(jù)不用通過驗(yàn)證就可以存儲到任意的位置
- 保證更新的單個文檔卫枝,而不是多個文檔
- 提供卓越的性能和可擴(kuò)展性
- 使用JOSN數(shù)據(jù)對象進(jìn)行查詢
- 是一種新型的技術(shù)
SQL數(shù)據(jù)庫適合那些需求確定和對數(shù)據(jù)完整性要去嚴(yán)格的項(xiàng)目煎饼。NoSQL數(shù)據(jù)庫適用于那些對速度和可擴(kuò)展性比較看重的那些不相關(guān)的,不確定和不斷發(fā)展的需求校赤。簡單來說就是:
- SQL是精確的吆玖。它最適合于具有精確標(biāo)準(zhǔn)的定義明確的項(xiàng)目。典型的使用場景是在線商店和銀行系統(tǒng)马篮。
- NoSQL是多變的沾乘。它最適合于具有不確定需求的數(shù)據(jù)。典型的使用場景是社交網(wǎng)絡(luò)浑测,客戶管理和網(wǎng)絡(luò)分析系統(tǒng)翅阵。
很少有項(xiàng)目能夠很好的適用于一種數(shù)據(jù)庫。如果你對數(shù)據(jù)的需求比較小或是非標(biāo)準(zhǔn)化的數(shù)據(jù)任何一種數(shù)據(jù)庫都是可以的。你比我更了解你的項(xiàng)目掷匠,我不建議你將SQL上的數(shù)據(jù)移植到NoSQL上反之亦然读慎,除非它能夠提供非常可觀的收益槐雾。當(dāng)然選擇權(quán)在于你自己。在項(xiàng)目的一開始就要考慮好使用它們的利弊幅狮,這樣才不會導(dǎo)致選擇錯誤募强。
場景一:通訊記錄
我們來重新的定義操作并基于SQL實(shí)現(xiàn)通訊錄系統(tǒng)。我們初始簡單的定義contact
表擁有如下幾個字段;
- id
- title
- firstname
- lastname
- gender
- telephone
- address1
- address2
- address3
- city
- region
- zipcode
- country
問題一:很少有人只擁有一個手機(jī)號崇摄∏嬷担或許我們可以再添加三個字段:固定電話,移動電話和工作電話逐抑,但是無論我們給一個聯(lián)系人分配了多少個字段總會有人需要更多鸠儿。我們需要創(chuàng)建一個單獨(dú)的telephone
表,這樣就可以給一個聯(lián)系人存多個號碼了厕氨。這樣也就規(guī)范化了我們的數(shù)據(jù)— 我們不需要一個沒有電話的聯(lián)系人:
- contact_id
- name (說明字段:固定进每,工作,私人等.)
- number
問題二:對于聯(lián)系人郵箱我們也會遇到上述問題命斧,因此我們也需要創(chuàng)建一個email
的表:
- contact_id
- name (說明字段:固定田晚,工作,私人等.)
- address
問題三:我們在填寫聯(lián)系人信息是我們并不希望填寫他的地理位置国葬,或者我們想記錄他工作贤徒、生活、旅游的地方等汇四。因此我們需要一個address
表:
- contact_id
- name (text such as home, office, etc.)
- address1
- address2
- address3
- city
- region
- zipcode
- country
我們原先設(shè)計(jì)的contact
表就精簡為:
- id
- title
- firstname
- lastname
- gender
好了接奈,我們已經(jīng)設(shè)計(jì)了一個規(guī)范化的數(shù)據(jù)庫,可以用來存儲任何一個聯(lián)系人的電話號碼通孽,郵箱地址和住址了序宦。但是......
模式是固定不變的
我們并沒有考慮到聯(lián)系人的生日,公司或者職位利虫。不管我們添加多少個字段挨厚,我們會得到更多的需求:備注,周年紀(jì)念日糠惫,關(guān)系疫剃,社交賬號,喜歡巧克力的種類等等硼讽。預(yù)測每一個需求對于我們來說是非常困難的巢价,因此我們需要創(chuàng)建一張表其中存儲的形式是鍵值對來應(yīng)對不斷增加的需求。
數(shù)據(jù)是碎片化的
對于開發(fā)人員和系統(tǒng)管理員來說不斷地檢查數(shù)據(jù)庫是比較麻煩的。程序的邏輯會變得更復(fù)雜效率更慢壤躲,因?yàn)槭褂靡粭lselect
語句來JOIN
多個表來取出一個聯(lián)系人的全部信息不太實(shí)際城菊。(當(dāng)然這也是可以實(shí)現(xiàn)的,但是當(dāng)一個聯(lián)系人中國包含電話號碼碉克,郵件地址和住址信息時:如果一個人有3個電話號碼凌唬,五個郵箱和兩個住址,那么SQL查詢會產(chǎn)生30個結(jié)果漏麦,也就是說說這樣的效率會很慢客税。)
最后,全文搜索是非常困難的撕贞。如果一個人要查詢一個字符型:favorite更耻,我們需要依次查詢上述的四張表判斷是否是一個聯(lián)系人的姓名,電話捏膨,郵件或者地址依據(jù)這些把結(jié)果進(jìn)行排序秧均。如果你使用過WordPress
的搜索,你就會發(fā)現(xiàn)是都么的煩人了号涯!
使用NoSQL來替代SQL
我們的聯(lián)系人關(guān)注的是人這個實(shí)體目胡。然而關(guān)于人的信息是不可預(yù)測的并且在不同的階段的需求也會不一樣。如果我們使用NoSQL數(shù)據(jù)庫會比較方便链快,NoSQL將一個人的信息存儲為一個文檔并放入contacts
的集合中:
{
name: [
"Billy", "Bob", "Jones"
],
company: "Fake Goods Corp",
jobtitle: "Vice President of Data Management",
telephone: {
home: "0123456789",
mobile: "9876543210",
work: "2244668800"
},
email: {
personal: "bob@myhomeemail.net",
work: "bob@myworkemail.com"
},
address: {
home: {
line1: "10 Non-Existent Street",
city: "Nowhere",
country: "Australia"
}
},
birthdate: ISODate("1980-01-01T00:00:00.000Z"),
twitter: '@bobsfakeaccount',
note: "Don't trust this guy",
weight: "200lb",
photo: "52e86ad749e0b817d25c8892.jpg"
}
在這個示例中讶隐,我們沒有存儲這個人的性別和職銜,并且可以添加一些別的聯(lián)系人沒用的信息久又。在NoSQL中這樣的存儲是合法的巫延,并且我們可以按照各人的意愿來添加和刪除一個字段。
因?yàn)橐粋€聯(lián)系人存儲在一個文檔中地消,因此我們可以使用一個查詢語句取出一個人的所有信息炉峰。對于全文搜索,在MongoDB中我們可以在contact
的字段中定義一個索引:
db.contact.createIndex({ "$**": "text" });
然后我們就可以使用如下的語句進(jìn)行全文搜索:
db.contact.find({
$text: { $search: "something" }
});
場景二:社交網(wǎng)絡(luò)
一個典型的社交網(wǎng)絡(luò)使用的聯(lián)系人的信息是相似脉执,但是也會增加一些新的功能例如:社交網(wǎng)絡(luò)疼阔,狀態(tài)更新,私信和點(diǎn)贊半夷。這些功能會根據(jù)用戶的需求進(jìn)行添加或者刪除婆廊,預(yù)測用戶的需求對開發(fā)人員來說是非常困難的。
另外:
- 大多數(shù)的更新都有一個原始的出發(fā)點(diǎn):用戶巫橄。但是淘邻,對于開發(fā)人員來說一次性的把所有的回饋都進(jìn)行更新是不可能的。
- 不管用戶怎么想湘换,一個失敗的版本并可能造成太大的經(jīng)濟(jì)損失宾舅。一個應(yīng)用的接口設(shè)計(jì)和功能表現(xiàn)是比數(shù)據(jù)的完整性的優(yōu)先級要高统阿。
因此,NoSQL是一個不錯的選擇筹我。數(shù)據(jù)庫允許我們存儲不同類型的數(shù)據(jù)以便于我們快速的開發(fā)出新的功能扶平。例如,因?yàn)樗械臄?shù)據(jù)狀態(tài)的更新都可以在status
的集合中的一個文檔中進(jìn)行:
{
user_id: ObjectID("65f82bda42e7b8c76f5c1969"),
update: [
{
date: ISODate("2015-09-18T10:02:47.620Z"),
text: "feeling more positive today"
},
{
date: ISODate("2015-09-17T13:14:20.789Z"),
text: "spending far too much time here"
}
{
date: ISODate("2015-09-17T12:33:02.132Z"),
text: "considering my life choices"
}
]
}
盡管對于這個文檔來說數(shù)據(jù)會變得多一些蔬蕊,但是我們可以僅僅取出文檔的一個子集结澄,例如:最新的狀態(tài)等。對于每一個用戶來說歷史記錄也會很容易搜索的到岸夯。
場景三:倉庫管理系統(tǒng)
現(xiàn)在概而,我們來分析一下一個倉庫的管理系統(tǒng)。我們需要記錄如下的信息:
- 貨物入庫的信息和存放的位置信息
- 貨物在倉庫中的移動囱修,例如:為相同的貨物分配相鄰的位置存放
- 貨物的擺放順序以及配送貨物之后的一系列問題。
數(shù)據(jù)需求:
- 保存貨物的基本信息例如:尺寸王悍、大小破镰、顏色等,這些不相關(guān)的數(shù)據(jù)我們要能夠用到任何的貨物上压储。我們不可能去考慮一些貨物個性化的信息例如:筆記本處理器的速度或者是一部手機(jī)電池的壽命鲜漩。
- 我們要盡可能的避免錯誤的發(fā)生。我們不能讓貨物憑空消失或者將貨物存放到已經(jīng)存放貨物的位置上去集惋。
- 以更加簡單的方式操作孕似。我們記錄將一件貨物從一個位置移動到另一個位置或者從A移動到B的操作是相同的。
因此刮刑,我們需要考慮對數(shù)據(jù)的完整性和對于事務(wù)的支持喉祭。目前來說也就是SQL能夠很好地滿足我們的需求。
總結(jié)
我希望上述的案例能夠?qū)δ阌幸欢ǖ膸椭拙睿敲恳粋€實(shí)際的項(xiàng)目都是不同的泛烙,對一無二的你需要自己去做決定選擇一種適合的。(盡管翘紊,對于我們開發(fā)人員來說我們不太愿意去改變我們現(xiàn)有的選擇蔽氨,無論新的技術(shù)有多好!O(∩_∩)O)
建議:去嘗試了解更多新的技術(shù)帆疟。這樣我們就可以非常有理由的選擇一種數(shù)據(jù)庫進(jìn)行開發(fā)鹉究。祝你好運(yùn)!