1. 程式人生 > >MySQL不香嗎,為什麼還要有noSQL?

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

本文始發於個人公眾號:**TechFlow**,原創不易,求個關注

今天是分散式專題的第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寶當中的商品詳情頁的圖(隨便選取,並非廣告,如有巧合,請付推廣費):

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

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

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

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

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

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

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

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

第一個方案的好處是我們不用建新的表,避免了表的冗餘,如果每一個需求都需要建新的表,顯然對於後續的維護是一個巨大的負擔。但是它的缺點是我們需要批量修正之前所有的資料,因為之前的資料裡沒有來源這個欄位。當然你也可以不加這個欄位,直接用id區分,但是這是不符合規範的,而且必然會留下安全隱患。

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

這兩個方案各有優缺點,似乎都還不錯,但坑爹的是它們都有一個共同的缺點,就是都會增加目前系統和查詢的複雜度。一個是要增加查詢時候傳入的欄位,一個是要發起額外的查詢,不論選擇哪一個,都會讓系統越來越複雜。到了後來,一個使用者請求傳來,會帶動數十個聯動請求,才能拼裝出完整的資料。現在最新版本的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一次查詢就可以獲取到了。

單純從使用上來說,它比關係型資料庫要方便了許多,但是它也並不是沒有缺點的。這其中一個很大的問題是,我們把所有資料都直接儲存在了文件當中,這一方面造成了資料的冗餘,另一方面也限制了拓展性。比如說,同一個商家下類似的商品不能共享圖片,而必須儲存多份,這造成了空間的浪費。再比如,假設我們希望支援使用者修改之前過去的評論會非常麻煩,因為我們必須要找到所有儲存了使用者評論的文件進行修改(假設在其他場景下也用到了使用者評論),這往往是跨系統並且非常不方便的。

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

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

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

總結

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

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

今天的文章就是這些,如果覺得有所收穫,請順手點個關注或者轉發吧,你們的舉手之勞對我來說很重要。

![](https://user-gold-cdn.xitu.io/2020/4/25/171b1280d8ef77f1?w=258&h=258&f=png&s=23988)