第3期 MongoDB與SQL存儲

一、 前言
MongoDB是一種流行的數(shù)據(jù)庫,可以在不受任何表格Schema模式的約束下工作。數(shù)據(jù)以類似JSON的格式存儲,并且可以包含不同類型的數(shù)據(jù)結構。但為了能夠充分利用MongoDB的優(yōu)勢,您必須了解并遵循一些基本的數(shù)據(jù)庫設計原則。在講解設計方法之前,我們必須首先了解MongoDB存儲數(shù)據(jù)的結構。
二、SQL概念與MongoDB概念對比
數(shù)據(jù)結構對于一個軟件來說是至關重要的,MongoDB 在概念模型上參考了 SQL數(shù)據(jù)庫,但并非完全相同。
2.1 數(shù)據(jù)如何存儲在MongoDB中
與傳統(tǒng)的RDBMS關系型數(shù)據(jù)庫不同,MongoDB并沒有表Table,行row和列column的概念。它將數(shù)據(jù)存儲在集合collections,文檔documents和字段fields中。下圖說明了與RDBMS類比的結構之間的關系:
| SQL概念 | MongoDB概念 | 說明 |
|---|---|---|
| database | database | database 數(shù)據(jù)庫,與SQL的數(shù)據(jù)庫(database)概念相同,一個數(shù)據(jù)庫包含多個集合(表) |
| table | collection | collection 集合,相當于SQL中的表(table),一個集合可以存放多個文檔(行)。不同之處就在于集合的結構- (schema)是動態(tài)的,不需要預先聲明一個嚴格的表結構。更重要的是,默認情況下 MongoDB 并不會對寫入的數(shù)據(jù)做任何schema的校驗。 |
| row | document | document 文檔,相當于SQL中的行(row),一個文檔由多個字段(列)組成,并采用bson(json)格式表示。 |
| column | field | field 字段,相當于SQL中的列(column),相比普通column的差別在于field的類型可以更加靈活,比如支持嵌套的文檔、數(shù)組。 |
此外,MongoDB中字段的類型是固定的、區(qū)分大小寫、并且文檔中的字段也是有序的。
2.2 SQL對應關系
| SQL概念 | MongoDB概念 | 說明 |
|---|---|---|
| primary key | _id | _id 主鍵,MongoDB 默認使用一個_id 字段來保證文檔的唯一性。 |
| foreign key | reference | 引用,勉強可以對應于 外鍵(foreign key) 的概念,之所以是勉強是因為 reference 并沒有實現(xiàn)任何外鍵的約束,而只是由客戶端(driver)自動進行關聯(lián)查詢、轉換的一個特殊類型。 |
| view | view | view 視圖,MongoDB 3.4 開始支持視圖,和 SQL 的視圖沒有什么差異,視圖是基于表/集合之上進行動態(tài)查詢的一層對象,可以是虛擬的,也可以是物理的(物化視圖)。 |
| index | index | index 索引,與SQL 的索引相同。 |
| join | $lookup | $lookup,這是一個聚合操作符,可以用于實現(xiàn)類似 SQL-join 連接的功能 |
| transaction | transaction | transaction 事務,從 MongoDB 4.0 版本開始,提供了對于事務的支持 |
| group by | aggregation | aggregation 聚合,MongoDB 提供了強大的聚合計算框架,group by 是其中的一類聚合操作。 |
三、BSON 數(shù)據(jù)類型
MongoDB 文檔可以使用 Javascript 對象表示,從格式上講,是基于 JSON 的。但是 JSON 也有自己的短板,比如無法支持像日期這樣的特定數(shù)據(jù)類型,因此 MongoDB 實際上使用的是一種擴展式的JSON,叫 BSON(Binary JSON)。
BSON 所支持的數(shù)據(jù)類型包括:

四、 數(shù)據(jù)庫設計技巧和竅門
4.1 規(guī)范化存儲與非規(guī)范化存儲
因為MongoDB使用文檔來存儲數(shù)據(jù),所以理解“規(guī)范化存儲“”和“非規(guī)范化存儲”的概念非常重要。
規(guī)范化存儲:-規(guī)范化意味著將數(shù)據(jù)存儲到多個集合collections中,并在它們之間設計關聯(lián)關系。數(shù)據(jù)保存之后,更新數(shù)據(jù)比較容易。但是在讀取數(shù)據(jù)的時候,規(guī)范化存儲的缺點就顯現(xiàn)出來。如果要從多個集合collections查找數(shù)據(jù),則必須執(zhí)行多個查詢,從而使讀取數(shù)據(jù)的速度變慢。(比如:將網(wǎng)頁標題、作者、內容分別存儲到不同的collections中)
非規(guī)范化存儲:-這種方式將若干對象數(shù)據(jù),以嵌套的方式存儲到單個文檔中。它在讀取數(shù)據(jù)的時候表現(xiàn)更好,但在寫入時會變慢。這種存儲數(shù)據(jù)的方式還將占用更多空間。(比如:將網(wǎng)頁標題、作者、內容分別存儲到同一個collection中)
所以在兩種存儲數(shù)據(jù)方式之間進行選擇之前,先評估一下你的應用數(shù)據(jù)庫的使用方式。如果您有一個不需要頻繁更新的數(shù)據(jù),更新的即時一致性不是很重要,但是在讀取時需要良好的性能,那么非規(guī)范化可能是明智的選擇。(比如:我們博客的博文,作者一旦保存之后,幾乎就不在進行頻繁的修改,但是面臨著讀者頻繁的讀取閱讀操作)
如果數(shù)據(jù)庫中的文檔數(shù)據(jù)需要不斷的更新,并且您希望在寫入時具有良好的性能,那么您可能需要考慮規(guī)范化存儲。(比如:需要頻繁修改數(shù)據(jù)的業(yè)務類系統(tǒng))
