MySQL它不香嗎,為什么還要NoSQL?
NoSQL 現在非常火,我看過的簡歷里面十個有九個都寫了熟悉 NoSQL,但是對于 NoSQL 背后的細節(jié)卻很少有人能講清楚,甚至連 NoSQL 里面的這個 No 是什么意思都很多人搞錯。
圖片來自 Pexels
這個 No 并不是 Not 的意思,而是 Not Only 的縮寫。不得不說這個縮寫實在是很坑爹,單從字面上應該沒人能猜出來它是這個意思。
而且即使解讀成 Not Only SQL,還是有點云里霧里,不是很能精準地 get 到它的點。
因為 SQL 的英文全寫是 Structured Query Language,也就是結構化查詢語言的意思。它可以認為是一門特殊的編程語言,但“不僅僅是 SQL”是啥意思?
的確令人費解,所以我們從字面意思上去理解是不行的,我們需要從實際應用場景去理解。
SQL 的應用場景是關系型數據庫,比如我們常用的 Oracle、MySQL,這些就是關系型數據庫。
我們理解數據庫的時候,往往會從表的結構入手去理解。數據庫當中存儲的是一張張的表,表呢是一行行數據組成的,而每一行數據都有固定的字段。
我想這點大家應該非常熟悉,即使沒有學過數據庫或者是像我這樣已經還給老師的,應該或多或少都有印象。
但是為什么它會被叫做關系型數據庫,而不是表結構數據庫呢?
因為在數據庫當中,關系要比表結構更重要。表結構只是一種形式,而數據庫當中核心的設計理念其實是關系。
這也是為什么我們學習數據庫的時候都需要從 ER 圖開始,而不是上來就講數據庫使用的方法,或者是 SQL 語言的細節(jié)。
如果你想不明白這句話的含義,也沒有關系,我們先放一放,最后再回到這個話題來。
問題來了,我們知道了常用的 SQL 數據庫是關系型數據庫,那么 NoSQL 代表的數據庫又是什么呢?
關于 NoSQL 概念我至少看到了兩種說法:
- 非關系型數據庫
- 文檔型數據庫
我個人在理解的時候覺得這兩種說法都不是非常完美,但相比之下顯然是第二種更好,因為第一種說法完全沒有給我們提供任何信息。
文檔型數據庫這里的文檔,并不是我們常規(guī)理解的一篇文檔的含義,而是指的數據存儲的結構和核心邏輯。
一個生動的例子
和大多數技術上的概念一樣,NoSQL 也比較晦澀,很難單純用語言將它描述清楚。
所以我決定舉一個生動活潑,大家都耳熟能詳的例子——就是萬能的 X 寶。
下面是一張 X 寶當中的商品詳情頁的圖(隨便選取,并非廣告,如有巧合,請付推廣費):
這張圖大家應該都很熟悉了,在我們平時的網上購物的活動當中,一定見過了許多次。
它看起來有些眼花繚亂,我們把上面的內容做個抽象和精簡,畫成一張草圖,它大概是這樣的(的確有些草率):
也就是說我們把一個商品詳情頁展示的內容大概分成了三個部分:
- 商品圖
- 商品的一些介紹說明
- 用戶的評論
各大電商公司商品詳情頁的設計大同小異,也許有些細節(jié)不太一樣,但是整體上的模塊都相差不大。
為了簡化問題,我們就假設商品詳情頁需要關聯(lián)圖片信息、文字說明和用戶評論這三張表。
其實這樣劃分不太科學,比如文字介紹和商品圖可以都存在商品詳情頁的表中。
比如除了這些信息之外,還有商品的售賣信息,比如庫存、價格、當前的優(yōu)惠、活動等等,但是這些和我們最后的結論關系不大,可以簡單這么理解。
根據上面的劃分方式,我們應該根據 itemID 去查詢商品的圖片、文字以及評論信息,這從表面上看當然沒有問題。
但實際上這是有問題的,問題在于這些數據都不是一對一的關系,而是一對多的關系。
比如頭部展示的圖片往往不止一張,文字說明可能也不止一段,同樣用戶的評論可能也不止一條。這個問題怎么解決呢?
你可能會想出辦法來,這不難啊,我們在 img 和 text 以及 comment 的表里都加入 itemID 這個字段,在我們查詢的時候通過 itemID 進行關聯(lián),不就 OK 了么?
這樣做當然可以,假設你是負責這個項目的程序員,你做出了這個更新,成功上線了之后,產品又給你提了一個新的需求。
她說我想要在文字介紹和用戶評論里面都展示圖片,雖然系統(tǒng)一開始不是這么設計的,但是我不管,我就是需要,立刻馬上。
你翻了好一會白眼,冷靜了許久,想了想,終于想到了兩種方案:
- 第一個方案是在目前的圖片表上加上字段,用來判斷圖片的用途是詳情頁展示還是評論頁展示,把之后要加的文本介紹和評論頁中的圖片依然存在這張表上。
- 第二個方案是重新建新的表,專表專用,專門負責存放評論頁和說明頁的圖片。
第一個方案的好處是我們不用建新的表,避免了表的冗余,如果每一個需求都需要建新的表,顯然對于后續(xù)的維護是一個巨大的負擔。
但是它的缺點是我們需要批量修正之前所有的數據,因為之前的數據里沒有來源這個字段。
當然你也可以不加這個字段,直接用 ID 區(qū)分,但是這是不符合規(guī)范的,而且必然會留下安全隱患。
第二個方案的優(yōu)點是操作簡單,不需要變更之前的數據,安全風險較小,但問題是需要占用新的資源,利用率低。
因為有些詳情頁的圖片和頂部的圖片是可以共用的,這樣分開存儲的話就需要存儲多份。
這兩個方案各有優(yōu)缺點,似乎都還不錯,但坑爹的是它們都有一個共同的缺點,就是都會增加目前系統(tǒng)和查詢的復雜度。
一個是要增加查詢時候傳入的字段,一個是要發(fā)起額外的查詢,不論選擇哪一個,都會讓系統(tǒng)越來越復雜。
到了后來,一個用戶請求傳來,會帶動數十個聯(lián)動請求,才能拼裝出完整的數據。
現在最新版本的 X 寶的詳情頁商品介紹的部分一律用圖片展示,沒有了文字,也許背后就是受到這個問題的驅動。
我們回顧一下這個例子,為什么我們的查詢會很復雜,其實就和數據庫的核心理念有關。
關系型數據庫存儲的數據是關系,在這個問題當中,我們一個詳情頁的查詢,需要查詢商品和圖片的關系,商品和說明的關系,商品和評論的關系,評論和圖片的關系等等。
也就是說我們最終看到的頁面,其實是這一系列關系擰在一起的結果,每一次查詢的背后都是一個關系分解再合并的過程,因此會非常復雜。
文檔型數據庫
我們剛才看了關系型數據庫在電商場景下的問題,我們再來看下文檔型數據庫在同樣場景下的表現。
和關系型數據庫不同,文檔型數據庫存儲的核心是文檔。當然這里的文檔指的不是我們通常意義上的文檔,而是 Json 或者是 XML 格式的數據。在目前的 NoSQL 數據庫當中,Json 類型的數據更加常用一些。
我們還用剛才詳情頁的例子來看下在 NoSQL 數據庫當中,這份數據是如何存儲的:
- {
- "itemID": 123,
- "itemName": "iPad Pro",
- "topImgs": ["imgs1.path", "imgs2.path"],
- "desc": [{"text": "iPad Pro", "img": ""}, {"text": "2020 new version", "img": "imgs1.path"}],
- "comments": [{"userName": "chengzhi", "comment": "good product", "imgs": ["imgs3.path", "img4.path"]}]
- }
你看,在文檔型數據庫當中剛才復雜的、需要經過多次查詢經過一系列處理才可以擰到一起的數據,我們通過 itemID 一次查詢就可以獲取到了。
單純從使用上來說,它比關系型數據庫要方便了許多,但是它也并不是沒有缺點的。
這其中一個很大的問題是,我們把所有數據都直接存儲在了文檔當中,這一方面造成了數據的冗余,另一方面也限制了拓展性。
比如說,同一個商家下類似的商品不能共享圖片,而必須存儲多份,這造成了空間的浪費。
再比如,假設我們希望支持用戶修改之前過去的評論會非常麻煩,因為我們必須要找到所有存儲了用戶評論的文檔進行修改(假設在其他場景下也用到了用戶評論),這往往是跨系統(tǒng)并且非常不方便的。
這個問題也并不是不可解的,比如我們可以把文檔當中存儲的具體數據換成一個 ID。
比如 Comment 當中不再存儲具體的圖片和評論信息,而存儲一個評論的 ID,在使用的時候再去關聯(lián)。
由于文檔型數據庫由于架構的原因,對于關聯(lián)的支持并不好,往往需要我們手動根據 ID 再去查詢來模擬連接,這也會帶來額外的開銷。
另外一個小瑕疵是在文檔型數據庫當中我們訪問數據的路徑變長了,舉個例子,加入我們要獲取商品評論當中的第二條中的第一張圖片。
我們需要寫成 item['comments'][1]['imgs'][0],而在關系型數據庫當中,由于圖片是通過關系直接查詢得到的,因此要方便一些。
除了這些之外,NoSQL 數據庫發(fā)展的年限和 MySQL 這些較成熟的關系型數據庫相比要短得多,因此支持的特性相對比較少。
總結
通過一個例子,我們很生動地對比了關系型數據庫和 NoSQL 數據庫之間的差別。
為什么我們在學習數據庫的時候需要先從 ER 圖開始,而不是直接學習數據庫的原理和它的使用方法呢?我想理解了上面的例子之后,再來看這個問題應該會簡單許多。
因為關系型數據庫的核心邏輯就是存儲關系,使用規(guī)范、各種技巧和特性,本質上都是圍繞這個核心展開的。
如果我們沒有 Get 到這一層就來使用數據庫很容易走偏,很多匪夷所思的操作就是這么來的。
比如有人在數據庫當中存儲前端頁面的代碼,比如把 ID 拼接成一個字符串來實現存儲多個值等等。
這也說明了經典教材上的內容沒有廢話,每一個章節(jié)都有它預期的作用,因此當我們覺得某些內容沒有用的時候,可能并不是教材錯了,只是我們沒有理解到位。
作者:梁唐
編輯:陶家龍
出處:轉載自微信公眾號 TechFlow(ID:techflow2019)