天天看點

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

什麼是MongoDB ?

MongoDB 是一個開源的文檔資料庫,它基于 C++ 語言編寫,性能高,可用性強,能夠自動擴充。

MongoDB 是最流行的 NoSQL 資料庫之一,原生支援分布式叢集架構,特别适合處理大資料,阿裡巴巴、騰訊、頭條、Twitter、Google、Facebook 等一線網際網路公司都在使用 MongoDB 資料庫。

與 HBase 相比,MongoDB 可以存儲具有更加複雜的資料結構的資料,具有很強的資料描述能力。MongoDB 提供了豐富的操作功能,但是它沒有類似于 SQL 的操作語言,文法規則相對比較複雜。

MongoDB(來自英文單詞“Humongous”,中文含義為“龐大”)是可以應用于各種規模的企業、各個行業以及各類應用程式的開源資料庫。

MongoDB的優勢

MongoDB 使用廣泛

MongoDB 是目前 NoSQL 資料庫中使用最廣泛的資料庫之一,根據 DB-Engines 2020 年 9 月份釋出的全球資料庫排名(見圖 1),前五名依次是 Oracle、MySQL、Microsoft SQL Server、PostgreSQL、MongoDB ,此排名順序已經持續很長時間,MongoDB 排名第五,9月份 MongoDB 的分數依然保持增長,而且還是整個排行榜中增長幅度最大的一個。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

MongoDB 性能高

MongoDB 是一個開源文檔資料庫,是用 C++ 語言編寫的非關系型資料庫。其特點是高性能、高可用、可伸縮、易部署、易使用,存儲資料十分友善,主要特性有:面向集合存儲,易于存儲對象類型的資料,模式自由,支援動态查詢,支援完全索引,支援複制和故障恢複,使用高效的二進制資料存儲,檔案存儲格式為 BSON ( 一種 JSON 的擴充)等。

MongoDB 提供高性能資料讀寫功能,并且性能還在不斷地提升。根據官方提供的 MongoDB 3.0 性能測試報告,在 YCSB 測試中,MongoDB 3.0 在多線程、批量插入場景下的處理速度比 MongoDB 2.6 快 7 倍。

關于讀寫與響應時間的具體測試結果參見圖 2。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

​ 圖 2:MongoDB 2.6 與 3.0 讀寫性能與響應時間性能測試

MongoDB 支援分布式

在生産過程中,因機器故障導緻系統當機的問題不可避免;集中式系統在計算能力和存儲能力方面的瓶頸,也無法滿足目前的資料量爆發式增長的需求。這兩個問題就是系統對高可用和可伸縮架構的需求,MongoDB 在原生上就可滿足這兩方面的需求。

MongoDB 的高可用性展現在對副本集 Replication 的支援上,可伸縮性展現在分片叢集的部署方式上。

MongoDB 的 Replication 集提供自動故障轉移和資料備援服務,Replication 結構可以保證資料庫中的全部資料都會有多份備份,這與 HDFS 分布式檔案系統的備份機制比較類似。采用副本集的叢集中具有主(Master)、從(Slaver)、仲裁(Arbiter)三種角色。

主從關系(Master-Slaver) 負責資料的同步和讀寫分離;Arbiter 服務負責心跳(Heartbeat)監控,Master 當機時可将 Slaver 切換到 Mas 血狀态,繼續提供資料的服務,完成了資料的高可用需求。

當需要存儲大量的資料時,主從伺服器都需要存儲全部資料,可能會出現寫性能問題。同時, Replication 主要解決的是讀資料高可用方面的問題,在對資料庫查詢時也隻限制在一台伺服器上, 并不能支援一次查詢多台資料庫伺服器,并沒有滿足資料庫讀寫操作的分布式需求。

MongoDB 提供水準可伸縮性功能的是分片(Shard)。分片與在 HDFS 分布式檔案系統中上傳檔案會将檔案切成 128MB(Hadoop2.x 預設配置)相似,通過将資料切成數片(Sharding)寫入不同的分片節點,完成分布式寫的操作。同時,MongoDB 在讀取時提供了分布式讀的操作,這個功能與 HDFS 的分布式讀寫十分類似。

MongoDB 便于開發

MongoDB 對開發者十分友好,便于使用。支援豐富的查詢語言、資料聚合、文本搜尋和地理空間查詢,使用者可以建立豐富的索引來提升查詢速度,MongoDB 被稱為最像關系資料庫的非關系資料庫。

MongoDB 允許使用者在服務端執行腳本,可以用 Javascript 編寫某個函數,直接在服務端執行,也可以把函數的定義存儲在服務端,使用時直接調用即可。MongoDB 支援各種程式設計語言,包括 Ruby、Python、Java、C++、PHP、C# 等。

Robomongo(MongoDB可視化工具)簡介

Robomongo 是一個界面友好且免費的 MongoDB 可視化工具,可在 Robomongo 官網下載下傳此軟體,其安裝過程十分簡單,安裝好的界面如下圖所示。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

在 MongoDB Connections 視窗單擊滑鼠右鍵添加 MongoDB 資料庫,設定如下圖所示。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

連接配接成功後,MongoDB 中所有資料庫以及集合均顯示在左側導航欄,如圖下所示。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

從上圖中可以看到 Robomango 提供可視化的界面将資料庫中的文檔顯示出來,在集合上單擊滑鼠右鍵可以顯示提供的集合操作。

使用 Robomango,初學者能更容易了解 MongoDB 資料庫的概念。

MongoDB的文檔資料模型

傳統的文檔資料庫(Document Storage)概念的提岀要追溯到 1989 年,Lotus 提出的 Notes 産品被稱為文檔資料庫,這種文檔資料庫常用于管理文檔,如 Word、建立工作流任務等。

文檔資料庫差別于傳統的其他資料庫,它可用來管理文檔,尤其擅長處理各種非結構化的文檔資料。在傳統的資料庫中,資訊被分割成離散的資料段,而在文檔資料庫中,文檔是處理資訊的基本機關。

傳統的文檔資料庫與 20 世紀 50 ~ 60 年代管理資料的檔案系統不同,文檔資料庫仍屬于資料庫範疇。

首先,檔案系統中的檔案基本上對應于某個應用程式。當不同的應用程式所需要的資料部分相同時,也必須建立各自的檔案,而不能共享資料,而文檔資料庫可以共享相同的資料。是以,檔案系統比文檔資料庫資料備援度更大,更浪費存儲空間,且更難于管理維護。

其次,檔案系統中的檔案是為某一特定應用服務的,是以,要想對現有的資料再增加一些新的應用是很困難的,系統難以擴充,資料和程式缺乏獨立性。而文檔資料庫具有資料的實體獨立性和邏輯獨立性,資料和程式分離。

NoSQL 中的文檔資料庫

NoSQL 中的文檔資料庫(以下文檔資料庫均指 NoSQL 中的文檔資料庫)與傳統的文檔資料庫不是同一種産品,NoSQL 中的文檔資料庫(MongoDB)有自己特定的資料存儲結構及操作要求。

在傳統資料庫的發展過程中,基本都是出現一種資料模型,再依據資料模型,開發出相關的資料庫,例如,層次資料庫是建立在層次資料模型的基礎上,關系資料庫是建立在關系資料模型的基礎上的。NoSQL 中文檔資料庫的出現也是建立在文檔資料模型的基礎上的。

NoSQL 中的文檔資料庫與傳統的關系資料庫均建立在對磁盤讀寫的基礎上,實作對資料的各種操作。文檔資料庫的設計思路是盡可能地提升資料的讀寫性能,為此選擇性地保留了部分關系型資料庫的限制,通過減少讀寫過程的規則限制,提升了讀寫性能。

MongoDB 文檔資料模型

傳統的關系型資料庫需要對表結構進行預先定義和嚴格的要求,而這樣的嚴格要求,導緻了處理資料的過程更加煩瑣,甚至降低了執行效率。

在資料量達到一定規模的情況下,傳統關系型資料庫反應遲鈍,想解決這個問題就需要反其道而行之,盡可能去掉傳統關系型資料庫的各種規範限制,甚至事先無須定義資料存儲結構。

文檔存儲支援對結構化資料的通路,與關系模型不同的是,文檔存儲沒有強制的架構。文檔存儲以封包鍵值對的方式進行存儲,文檔存儲模型支援嵌套結構。

  • 例如,文檔存儲模型支援 XML 和 JSON 文檔,字段的“值”可以嵌套存儲其他文檔,也可存儲數組等複雜資料類型。

MongoDB 存儲的資料類型為 BSON,BSON 與 JSON 比較相似,文檔存儲模型也支援數組和鍵值對。

MongoDB 的文檔資料模型如圖下所示,MongoDB 的存儲邏輯結構為文檔,文檔中采用鍵值對結構,文檔中的 _id 為主鍵,預設建立主鍵索引。從 MongoDB 的邏輯結構可以看出,MongoDB 的相關操作大多通過指定鍵完成對值的操作。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

文檔資料庫無須事先定義資料存儲結構,這與鍵值資料庫和列族資料庫類似,隻需在存儲時采用指定的文檔結構即可。從上圖可以看出,一個

{}

中包含了若幹個鍵值對,大括号中的内容就被稱為一條文檔。

MongoDB的文檔存儲結構

MongoDB 文檔資料庫的存儲結構分為四個層次,從小到大依次是:鍵值對、文檔(document)、集合(collection)、資料庫(database)。

圖 1 描述了 MongoDB 的存儲與 MySQL 存儲的對應關系,可以看出,MongoDB中的文檔、集合、資料庫對應于關系資料庫中的行資料、表、資料庫。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

​ 圖 1:MongoDB 存儲與 Mysql 存儲的對比

鍵值對

文檔資料庫存儲結構的基本機關是鍵值對,具體包含資料和類型。鍵值對的資料包含鍵和值,鍵的格式一般為字元串,值的格式可以包含字元串、數值、數組、文檔等類型。

按照鍵值對的複雜程度,可以将鍵值對分為基本鍵值對和嵌套鍵值對。

  • 圖 2 中的鍵值對中的鍵為字元串,值為基本類型,這種鍵值對就稱為基本鍵值。
  • 嵌套鍵值對類型如圖 3 所示,從圖中可以看岀, contact 的鍵對應的值為一個文檔,文檔中又包含了相關的鍵值對,這種類型的鍵值對稱為嵌套鍵值對。
NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

​ 圖 2:MongoDB 文檔資料模型

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

​ 圖 3:嵌套鍵值對

鍵(Key)起唯一索引的作用,確定一個鍵值結構裡資料記錄的唯一性,同時也具有資訊記錄的作用。例如,country:“China”,用

:

實作了對一條位址的分割記錄,“country”起到了 “China”的唯一位址作用,另外,“country”作為鍵的内容說明了所對應内容的一些資訊。

值(Value)是鍵所對應的資料,其内容通過鍵來擷取,可存儲任何類型的資料,甚至可以為空。

鍵和值的組成就構成了鍵值對(Key-Value Pair)。它們之間的關系是一一對應的,如定義了 “country:China”鍵值對,"country”就隻能對應“China”,而不能對應“USA”。

文檔中鍵的命名規則如下。

  • UTF-8 格式字元串。
  • 不用有

    \0

    的字元串,習慣上不用

    .

    $

  • 以開頭的多為保留鍵,自定義時一般不以開頭。
  • 文檔鍵值對是有序的,MongoDB 中嚴格區分大小寫。

文檔

文檔是 MongoDB 的核心概念,是資料的基本單元,與關系資料庫中的行十分類似,但是比行要複雜。文檔是一組有序的鍵值對集合。文檔的資料結構與 JSON 基本相同,所有存儲在集合中的資料都是 BSON 格式。

BSON 是一種類 JSON 的二進制存儲格式,是 Binary JSON 的簡稱。 一個簡單的文檔例子如下:

MongoDB 中的資料具有靈活的架構,集合不強制要求文檔結構。但資料模組化的不同可能會影響程式性能和資料庫容量。文檔之間的關系是資料模組化需要考慮的重要因素。文檔與文檔之間 的關系包括嵌入和引用兩種。

下面舉一個關于顧客 patron 和位址 address 之間的例子,來說明在某些情況下,嵌入優于引用。

{
    _id: "joe",
    name: "Joe Bookreader"
}

{
    patron_id: "joe",
    street: "123 Fake Street",
    city: "Faketon",
    state: "MA",
    zip: "2345"
}
           

關系資料庫的資料模型在設計時,将 patron 和 address 分到兩個表中,在查詢時進行關聯, 這就是引用的使用方式。如果在實際查詢中,需要頻繁地通過 _id 獲得 address 資訊,那麼就需要頻繁地通過關聯引用來傳回查詢結果。在這種情況下,一個更合适的資料模型就是嵌入。

将 address 資訊嵌入 patron 資訊中,這樣通過一次查詢就可獲得完整的 patron 和 address 資訊,如下所示:

{
    _id: "joe",
    name: "Joe Bookreader",
    address: {
        street: "123 Fake Street",
        city: "Faketon”,
        state: nMAnz
        zip: T2345”
    }
}
           

如果具有多個 address,可以将其嵌入 patron 中,通過一次查詢就可獲得完整的 patron 和多個 address 資訊,如下所示:

{
    _id: "joe",
    name: "Joe Bookreader",
    addresses:[
        {
            street: "123 Fake Streetn,
            city: "Faketon",
            state: "MA",
            zip: "12345"
        },
        {
            street: "l Some Other Street",
            city: "Boston",
            state: "MA",
            zip: "12345"
        }
    ]
}
           

但在某種情況下,引用比嵌入更有優勢。下面舉一個圖書出版商與圖書資訊的例子,代碼如下:

{
    title: "MongoDB: The Definitive Guide",
    author: [ "Kristina Chodorow", "Mike Dirolfn"],
    published_date: ISODate("2010-09-24"),
    pages: 216,
    language: "English",
    publisher: {
        name: "O'Reilly Media",
        founded: 1980,
        location: "CA"
    }
}
{
    title: "50 Tips and Tricks for MongoDB Developer",
    author: "Kristina Chodorow",
    published_date: ISODate("2011-05-06"),
    pages: 68,
    language: "English",
    publisher: {
        name: "O'Reilly Media",
        founded: 1980,
        location: "CA"
    }
}
           

從上邊例子可以看出,嵌入式的關系導緻出版商的資訊重複釋出,這時可采用引用的方式描述集合之間的關系。使用引用時,關系的增長速度決定了引用的存儲位置。如果每個出版商的圖書數量很少且增長有限,那麼将圖書資訊存儲在出版商文檔中是可行的。

通過 books 存儲每本圖書的 id 資訊,就可以查詢到指定圖書出版商的指定圖書資訊,但如果圖書出版商的圖書數量很多, 則此資料模型将導緻可變的、不斷增長的數組 books,如下所示:

{
    name: "O'Reilly Media",
    founded: 1980,
    location: "CA",
    books: [123456789, 234567890, …]
}
{
    _id: 123456789,
    title: "MongoDE: The Definitive Guide",
    author: ["Kristina Chodorow", "Mike Dirolf"],
    published_date: ISODate("2010-09-24"),
    pages: 216,
    language: "English"
}
{
    _id: 234567890,
    title: "50 Tips and Tricks for MongoDB Developer",
    author: "Kristina Chodorow",
    published_date: ISODate("2011-05-06"),
    pages: 68,
    language: "English"
} 
           

為了避免可變的、不斷增長的數組,可以将出版商引用存放到圖書文檔中,如下所示:

{
    _id: "oreilly",
    name: "O'Reilly Media",
    founded: 1980,
    location: "CA"
}
{
    _id: 123456789,
    title: "MongoDB: The Definitive Guiden,
    author: [ "Kristina Chodorow", "Mike Dirolf"],
    published_date: ISODate("2010-09-24"),
    pages: 216,
    language: "English",
    publisher_id: "oreilly"
}
{
    _id: 234567890,
    title: "50 Tips and Tricks for MongoDB Developer",
    author: "Kristina Chodorow",
    published date: ISODate("2011-05-06"),
    pages: 68,
    language: "English",
    publisher_id: "oreilly"
}
           

集合

MongoDB 将文檔存儲在集合中,一個集合是一些文檔構成的對象。如果說 MongoDB 中的文檔類似于關系型資料庫中的“行”,那麼集合就如同“表”。

集合存在于資料庫中,沒有固定的結構,這意味着使用者對集合可以插入不同格式和類型的資料。但通常情況下插入集合的資料都會有一定的關聯性,即一個集合中的文檔應該具有相關性。

集合的結構如圖 4 所示。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

​ 圖 4:文檔資料庫中的一個集合

資料庫

在 MongoDB 中,資料庫由集合組成。一個 MongoDB 執行個體可承載多個資料庫,互相之間彼此獨立,在開發過程中,通常将一個應用的所有資料存儲到同一個資料庫中,MongoDB 将不同資料庫存放在不同檔案中。

資料庫結構示例如圖 5 所示。

NOSQL,MongoDB是什麼?什麼是MongoDB ?MongoDB的優勢Robomongo(MongoDB可視化工具)簡介MongoDB的文檔資料模型MongoDB的文檔存儲結構BSON對JSON做了哪些改進?

​ 圖 5:一個名為 DB 的資料庫的結構

BSON對JSON做了哪些改進?

我們說,MongoDB 存儲的資料格式與 JSON 十分類似,MongoDB 所采用的資料格式被稱為 BSON,是一種基于 JSON 的二進制序列化格式,用于 MongoDB 存儲文檔并進行遠端過程調用。

JSON 是一種網絡常用的資料格式,具有自描述性。JSON 的資料表示方式易于解析,但支援的資料類型有限。BSON 目前主要用于 MongoDB 中,選擇 JSON 進行改造的原因主要是 JSON 的通用性及 JSON 的 schemaless 的特性。

BSON 改進的主要特性有下面三點。

更快的周遊速度

BSON 對 JSON 的一個主要的改進是,在 BSON 元素的頭部有一個區域用來存儲元素的長度, 當周遊時,如果想跳過某個文檔進行讀取,就可以先讀取存儲在 BSON 元素頭部的元素的長度, 直接 seek 到指定的點上就完成了文檔的跳過。

在 JSON 中,要跳過一個文檔進行資料讀取,需要在對此文檔進行掃描的同時比對資料結構才可以完成跳過操作。

操作更簡易

如果要修改 JSON 中的一個值,如将 9 修改為 10,這實際是将一個字元變成了兩個,會導緻其後面的所有内容都向後移一位。

在 BSON 中,可以指定這個列為整型,那麼,當将 9 修正為 10 時,隻是在整型範圍内将數字進行修改,資料總長不會變化。

需要注意的是:如果數字從整型增大到長整型,還是會導緻資料總長增加。

支援更多的資料類型

BSON 在 JSON 的基礎上增加了很多額外的類型,BSON 增加了“byte array”資料類型。這使得二進制的存儲不再需要先進行 base64 轉換再存為 JSON,減少了計算開銷。

BSON 支援的資料類型如表所示。

類型 描述示例
NULL 表示空值或者不存在的字段,{“x” : null}
Boolean 布爾型有 true 和 false,{“x” : true}
Number 數值:用戶端預設使用 64 位浮點型數值。{“x” : 3.14} 或 {“x” : 3}。對于整型值,包括 NumberInt(4 位元組符号整數)或 NumberLong(8 位元組符号整數),使用者可以指定數值類型,{“x” : NumberInt(“3”)}
String 字元串:BSON 字元串是 UTF-8,{“x” : “中文”}
Regular Expression 正規表達式:文法與 JavaScript 的正規表達式相同,{“x” : /[cba]/}
Array 數組:使用“[]”表示,{“x” : [“a”, “b”, “c”]}
Object 内嵌文檔:文檔的值是嵌套文檔,{“a” : {“b” : 3}}
ObjectId 對象 id:對象 id 是一個 12 位元組的字元串,是文檔的唯一辨別,{“x” : objectId()}
BinaryData 二進制資料:二進制資料是一個任意位元組的字元串。它不能直接在 Shell 中使用。如果要将非 UTF-8 字元儲存到資料庫中,二進制資料是唯一的方式
JavaScript 代碼:查詢和文檔中可以包括任何 JavaScript 代碼,{“x” : function(){/…/}}
Data 日期:{“x” : new Date()}
Timestamp 時間戳:var a = new Timestamp()