MySQL不香嗎,為什麼還要有noSQL?

今天是分佈式專題的第14篇文章,我們一起來看看NoSQL數據庫。

其實我很早就想寫寫分佈式數據庫相關的文章,既是我現在正在學習的,也是我很感興趣的內容。但是談到分佈式數據庫,會涉及很多相關的技術細節,等把相關的一些細節寫明白的時候,已經十幾篇文章過去了XD。所以如果想要了解B/B+樹、LSMT、CAP等技術細節的,可以翻翻之前的文章。今天我們來聊聊NoSQL這個概念。

noSQL的大概意思

noSQL現在非常火,我看過的簡歷裡面十個有九個都寫了熟悉noSQL,但是對於noSQL背後的細節卻很少有人能講清楚,甚至連noSQL裡面的這個no是什麼意思都很多人搞錯。這個no並不是not的意思,而是not only的縮寫。不得不說這個縮寫實在是很坑爹,單從字面上應該沒人能猜出來它是這個意思。而且即使解讀成not only SQL,還是有點雲裡霧裡,不是很能精準地get到它的點。

因為SQL的英文全寫是structured query language,也就是結構化查詢語言的意思。它可以認為是一門特殊的編程語言,但“不僅僅是SQL”是啥意思?的確令人費解,所以我們從字面意思上去理解是不行的,我們需要從實際應用場景去理解。

SQL的應用場景是關係型數據庫,比如我們常用的Oracle、MySQL,這些就是關係型數據庫。我們理解數據庫的時候,往往會從表的結構入手去理解。數據庫當中存儲的是一張張的表,表呢是一行行數據組成的,而每一行數據都有固定的字段。我想這點大家應該非常熟悉,即使沒有學過數據庫或者是像我這樣已經還給老師的,應該或多或少都有印象。

但是為什麼它會被叫做關係型數據庫,而不是表結構數據庫呢?

因為在數據庫當中,關係要比表結構更重要。表結構只是一種形式,而數據庫當中核心的設計理念其實是關係。這也是為什麼我們學習數據庫的時候都需要從ER圖開始,而不是上來就講數據庫使用的方法,或者是SQL語言的細節。如果你想不明白這句話的含義,也沒有關係,我們先放一放,最後再回到這個話題來。

問題來了,我們知道了常用的SQL數據庫是關係型數據庫,那麼noSQL代表的數據庫又是什麼呢?

關於noSQL概念我至少看到了兩種說法,一種說法是

非關係型數據庫,另一種說法是文檔型數據庫。我個人在理解的時候覺得這兩種說法都不是非常完美,但相比之下顯然是第二種更好,因為第一種說法完全沒有給我們提供任何信息。文檔型數據庫這裡的文檔,並不是我們常規理解的一篇文檔的含義,而是指的數據存儲的結構和核心邏輯。

一個生動的例子

和大多數技術上的概念一樣,noSQL也比較晦澀,很難單純用語言將它描述清楚。所以我決定舉一個生動活潑,大家都耳熟能詳的例子——就是萬能的X寶。

下面是一張X寶當中的商品詳情頁的圖(隨便選取,並非廣告,如有巧合,請付推廣費):

MySQL不香嗎,為什麼還要有noSQL?

這張圖大家應該都很熟悉了,在我們平時的網上購物的活動當中,一定見過了許多次。它看起來有些眼花繚亂,我們把上面的內容做個抽象和精簡,畫成一張草圖,它大概是這樣的(的確有些草率):

MySQL不香嗎,為什麼還要有noSQL?

也就是說我們把一個商品詳情頁展示的內容大概分成了三個部分,一個部分是商品圖,一個部分是商品的一些介紹說明,還有一個部分是用戶的評論。各大電商公司商品詳情頁的設計大同小異,也許有些細節不太一樣,但是整體上的模塊都相差不大。

為了簡化問題,我們就假設商品詳情頁需要關聯圖片信息、文字說明和用戶評論這三張表。其實這樣劃分不太科學,比如文字介紹和商品圖可以都存在商品詳情頁的表中,比如除了這些信息之外,還有商品的售賣信息,比如庫存、價格、當前的優惠、活動等等,但是這些和我們最後的結論關係不大,可以簡單這麼理解。

根據上面的劃分方式,我們應該根據itemId去查詢商品的圖片、文字以及評論信息,這從表面上看當然沒有問題。但實際上這是有問題的,問題在於這些數據都不是一對一的關係,而是一對多的關係

比如頭部展示的圖片往往不止一張,文字說明可能也不止一段,同樣用戶的評論可能也不止一條。這個問題怎麼解決呢?

你可能會想出辦法來,這不難啊,我們在img和text以及comment的表裡都加入itemId這個字段,在我們查詢的時候通過itemId進行關聯,不就OK了麼?

這樣做當然可以,假設你是負責這個項目的程序員,你做出了這個更新,成功上線了之後,產品又給你提了一個新的需求。她說我想要在文字介紹和用戶評論裡面都展示圖片,雖然系統一開始不是這麼設計的,但是我不管,我就是需要,立刻馬上。

你翻了好一會白眼,冷靜了許久,想了想,終於想到了兩種方案,第一個方案是在目前的圖片表上加上字段,用來判斷圖片的用途是詳情頁展示還是評論頁展示,把之後要加的文本介紹和評論頁中的圖片依然存在這張表上。第二個方案是重新建新的表,專表專用,專門負責存放評論頁和說明頁的圖片。

第一個方案的好處是我們不用建新的表,避免了表的冗餘,如果每一個需求都需要建新的表,顯然對於後續的維護是一個巨大的負擔。但是它的缺點是我們需要批量修正之前所有的數據

,因為之前的數據裡沒有來源這個字段。當然你也可以不加這個字段,直接用id區分,但是這是不符合規範的,而且必然會留下安全隱患。

第二個方案的優點是操作簡單,不需要變更之前的數據,安全風險較小,但問題是需要佔用新的資源,利用率低,因為有些詳情頁的圖片和頂部的圖片是可以共用的,這樣分開存儲的話就需要存儲多份。

這兩個方案各有優缺點,似乎都還不錯,但坑爹的是它們都有一個共同的缺點,就是都會增加目前系統和查詢的複雜度。一個是要增加查詢時候傳入的字段,一個是要發起額外的查詢,不論選擇哪一個,都會讓系統越來越複雜。到了後來,一個用戶請求傳來,會帶動數十個聯動請求,才能拼裝出完整的數據。現在最新版本的X寶的詳情頁商品介紹的部分一律用圖片展示,沒有了文字,也許背後就是受到這個問題的驅動。

我們回顧一下這個例子,為什麼我們的查詢會很複雜,其實就和數據庫的核心理念有關。關係型數據庫存儲的數據是關係,在這個問題當中,我們一個詳情頁的查詢,需要查詢商品和圖片的關係,商品和說明的關係,商品和評論的關係,評論和圖片的關係等等。也就是說我們最終看到的頁面,其實是這一系列關係擰在一起的結果,每一次查詢的背後都是一個關係分解再合併的過程,因此會非常複雜。

文檔型數據庫

我們剛才看了關係型數據庫在電商場景下的問題,我們再來看下文檔型數據庫在同樣場景下的表現。

和關係型數據庫不同,文檔型數據庫存儲的核心是文檔。當然這裡的文檔指的不是我們通常意義上的文檔,而是json或者是xml格式的數據。在目前的noSQL數據庫當中,json類型的數據更加常用一些。我們還用剛才詳情頁的例子來看下在noSQL數據庫當中,這份數據是如何存儲的:

<code>{
  "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"]}]
}/<code>

你看,在文檔型數據庫當中剛才複雜的、需要經過多次查詢經過一系列處理才可以擰到一起的數據,我們通過itemID一次查詢就可以獲取到了

單純從使用上來說,它比關係型數據庫要方便了許多,但是它也並不是沒有缺點的。這其中一個很大的問題是,我們把所有數據都直接存儲在了文檔當中,這一方面造成了

數據的冗餘,另一方面也限制了拓展性。比如說,同一個商家下類似的商品不能共享圖片,而必須存儲多份,這造成了空間的浪費。再比如,假設我們希望支持用戶修改之前過去的評論會非常麻煩,因為我們必須要找到所有存儲了用戶評論的文檔進行修改(假設在其他場景下也用到了用戶評論),這往往是跨系統並且非常不方便的。

這個問題也並不是不可解的,比如我們可以把文檔當中存儲的具體數據換成一個id,比如comment當中不再存儲具體的圖片和評論信息,而存儲一個評論的id,在使用的時候再去關聯。由於文檔型數據庫由於架構的原因,對於關聯的支持並不好,往往需要我們手動根據ID再去查詢來模擬連接,這也會帶來額外的開銷。

另外一個小瑕疵是在文檔型數據庫當中我們訪問數據的路徑變長了,舉個例子,加入我們要獲取商品評論當中的第二條中的第一張圖片。我們需要寫成item['comments'][1]['imgs'][0],而在關係型數據庫當中,由於圖片是通過關係直接查詢得到的,因此要方便一些。

除了這些之外,noSQL數據庫發展的年限和MySQL這些較成熟的關係型數據庫相比要短得多,因此支持的特性相對比較少

總結

通過一個例子,我們很生動地對比了關係型數據庫和noSQL數據庫之間的差別。我們再回到文章開頭的那個問題,為什麼我們在學習數據庫的時候需要先從ER圖開始,而不是直接學習數據庫的原理和它的使用方法呢?

我想理解了上面的例子之後,再來看這個問題應該會簡單許多。因為關係型數據庫的核心邏輯就是存儲關係,使用規範、各種技巧和特性,本質上都是圍繞這個核心展開的。如果我們沒有get到這一層就來使用數據庫很容易走偏,很多匪夷所思的操作就是這麼來的,比如有人在數據庫當中存儲前端頁面的代碼,比如把id拼接成一個字符串來實現存儲多個值等等。這也說明了經典教材上的內容沒有廢話,每一個章節都有它預期的作用,因此當我們覺得某些內容沒有用的時候,可能並不是教材錯了,只是我們沒有理解到位。

今天的文章就是這些,如果覺得有所收穫,請順手點個

關注或者轉發吧,你們的舉手之勞對我來說很重要。


分享到:


相關文章: