NoSql數據庫這個概念聽聞許久了,也陸續看到很多公司和產品都在使用,優缺點似乎都被分析的清清楚楚。但我心里一直存有一個疑惑,它的出現究竟是為了解決什么問題?
這個疑惑非常大,為此我看了很多分析文章,但卻總感覺是隔靴搔癢。為了一探究竟,半年前我決定用Mongodb這個著名的NoSql數據庫做個產品試試。只有在真實的使用環境中才能得到最貼切的感受。
一晃眼,半年過去了,現在我能用親身的體會來談談NoSql數據庫存在的理由和試圖解決的問題了。就像所有的哲學思考都來源于對日常活動的觀察一樣,我們也從最基本的東西說起吧。
來看這樣一個業務要求,用戶可以為一本書打分,并且寫評論。熟悉數據庫結構設計的人看到這一句話腦子里應該瞬間就會出現下面這樣的表結構(我這里就不太講究了,大家意會即可):
用戶信息表,書籍信息表,用戶為書籍打分信息表,評論表。
現在假想要做一個顯示評論內容的頁面,上面會有用戶信息和相關書籍的信息,想必大家腦子里已經出現各種select和join了吧。
如果用NoSql還是同樣的設計的話,那你會驚喜的發現NoSql數據庫的性能簡直差到爆。性子火爆的估計當場就要掀桌。
什么破爛數據庫,不是號稱性能一流的嗎!
好吧,性能問題也就不說了,竟然連事務都不支持!?那我同時插入四張表的數據該怎么保持一致?開玩笑的吧!
NoSql數據庫此時默默的淚流滿面,冤枉啊……你別說,還真是冤枉它了。
先從最基本的設計元素說起,幾乎所有的NoSql數據庫都沒有表(table)的概念,取而代之的是文檔(document)。文檔是個什么東西?Mongodb的解釋,文檔是一個使用JSON格式以key-value方式存儲數據的結構,比如:
{ "item": "pencil", "qty": 500, "type": "no.2" }
看起來和表沒什么不同嘛?咳咳,JSON是支持嵌套結構的,比如可以把書籍信息和用戶打分的信息存到一起:
{
"id": "123zxcrweq2",
"title": "雪中悍刀行",
"author": "烽火戲諸侯",
"scores": [
{
"userid": "454zxcfwer1",
"nickname": "Allen",
"score": 3,
},
{
"userid": "678zxkiou1",
"nickname": "Judy",
"score": 4,
}
],
}
一堆document存儲到一起就叫做collection,而同一個collection里面的document可以不一樣。注意,這里也是重點概念。如果切換到關系型數據庫的話,相當于一張表里每一行數據的列都可以不一樣。這不是亂套了嗎?用不好確實會亂套的。
概念說完了,來看看面對下面這種產品要求的時候應該怎么辦。產品經理說了,要在書籍信息頁面看到所有評論,評論人的信息和打的分也要出現。
如果是關系數據庫,獲取數據的思路是這樣的:
1. 根據書籍Id取到書籍信息。
2. 根據書籍Id取到所有評論信息。
3. 根據評論信息中的用戶Id取到相關用戶的信息。
4. 根據書籍Id和用戶Id取到打分信息。
那在NoSql數據庫中如果我們用如下結構存儲數據的話……
{
"id": "123zxcrweq2",
"title": "雪中悍刀行",
"author": "烽火戲諸侯",
"comments": [
{
"author": {
"id": "454zxcfwer1",
"nickname": "Allen",
"avatarurl": "頭像1.png",
},
"score": 3,
"title": "書評1",
"content": "書評內容1",
},
{
"author": {
"id": "454zxcfwer1",
"nickname": "Judy",
"avatarurl": "頭像2.png",
},
"score": 4,
"title": "書評2",
"content": "書評內容2"
}
],
}
似乎只要根據書籍Id查詢一次就能得到結果了吧……明白為什么說NoSql數據庫效率高了嗎?一邊是從四個集合中查找數據,一邊是從一個集合中查找數據,這運行效率肉眼就能看出來差別了吧。
所以到這里我得到了一條設計心得,盡可能把一次展示所需的必要數據都存儲到一起。這是典型的空間換時間。所幸現在的科技條件下空間的價格非常低廉,所以很劃算。
根據這個設計結構,似乎也不需要事務的支持了,用戶為一本書籍打分只需要在一個document里面添加數據就夠了。
好,document特性的用處明白了,現在就來研究下NoSql數據庫另外一條原則的用途了,還記得是什么嗎?同一個collection里面的document可以不一樣。
還是從實際應用中來看,某日,產品經理說,書籍詳細信息頁面上還要顯示書評的創建時間。
如果使用關系數據庫該怎么辦?
1. 創建一個為Review表增加”creationtime“列的sql腳本。
2. 到數據庫中運行。
3. 修改相關代碼和存儲過程。
NoSql呢?
1. 在Comment結構實體中增加CreationTime,增加賦值代碼。
沒了,不需要去修改歷史數據,因為?同一個collection里面的document可以不一樣。那如果取到歷史數據怎么辦?Comment的CreationTime會被置為空。挺合理的,也不會產生什么危害。
大家都知道,互聯網產品的更新速度是非常快的,經常根據用戶反饋和市場情況調整產品形態,而數據結構也會經常發生變化。為了適應這種環境,如何處理歷史數據就成了老大難。還記得當年看到一個DBA在設計表的時候會留出幾個字段叫做”Reserved1,Reserved2……“,感覺好無厘頭,浪費空間,后來隨著產品功能的增加才明白這其實是經驗豐富的表現。如果用NoSql就不用這么糾結了。
總結一下,就我淺薄的使用經驗來看,NoSql的優點是:1. 在精心的設計下查詢性能巨好。2. 數據結構彈性十足,特別適合快速發展中的產品。
另外需要提醒一下,Mongodb不支持事務,所以務必在設計的時候考慮到這一點。核心業務數據盡可能通過結構設計做到數據插入的一致性。如果實在無法達成,請立即轉回去用關系數據庫,否則或早或晚你一定會后悔的。
文章列表