日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
[淺入淺出]MongoDB和WiredTiger

MongoDB 是目前主流的 NoSQL 數(shù)據(jù)庫之一,與關系型數(shù)據(jù)庫和其它的 NoSQL 不同,MongoDB 使用了面向文檔的數(shù)據(jù)存儲方式,將數(shù)據(jù)以類似 JSON 的方式存儲在磁盤上,因為項目上的一些歷史遺留問題,作者在最近的工作中也不得不經(jīng)常與 MongoDB 打交道,這也是這篇文章出現(xiàn)的原因。

雖然在之前也對 MongoDB 有所了解,但是真正在項目中大規(guī)模使用還是***次,使用過程中也暴露了大量的問題,不過在這里,我們主要對 MongoDB 中的一些重要概念的原理進行介紹,也會與 MySQL 這種傳統(tǒng)的關系型數(shù)據(jù)庫做一個對比,讓讀者自行判斷它們之間的優(yōu)勢和劣勢。

概述

MongoDB 雖然也是數(shù)據(jù)庫,但是它與傳統(tǒng)的 RDBMS 相比有著巨大的不同,很多開發(fā)者都認為或者被灌輸了一種思想,MongoDB 這種無 Scheme 的數(shù)據(jù)庫相比 RDBMS 有著巨大的性能提升,這個判斷其實是一種誤解;因為數(shù)據(jù)庫的性能不止與數(shù)據(jù)庫本身的設計有關系,還與開發(fā)者對表結構和索引的設計、存儲引擎的選擇和業(yè)務有著巨大的關系,如果認為 僅進行了數(shù)據(jù)庫的替換就能得到數(shù)量級的性能提升 ,那還是太年輕了。

架構

現(xiàn)有流行的數(shù)據(jù)庫其實都有著非常相似的架構,MongoDB 其實就與 MySQL 中的架構相差不多,底層都使用了『可插拔』的存儲引擎以滿足用戶的不同需要。

用戶可以根據(jù)表中的數(shù)據(jù)特征選擇不同的存儲引擎,它們可以在同一個 MongoDB 的實例中使用;在***版本的 MongoDB 中使用了 WiredTiger 作為默認的存儲引擎,WiredTiger 提供了不同粒度的并發(fā)控制和壓縮機制,能夠為不同種類的應用提供了***的性能和存儲效率。

在不同的存儲引擎上層的就是 MongoDB 的數(shù)據(jù)模型和查詢語言了,與關系型數(shù)據(jù)庫不同,由于 MongoDB 對數(shù)據(jù)的存儲與 RDBMS 有較大的差異,所以它創(chuàng)建了一套不同的查詢語言;雖然 MongoDB 查詢語言非常強大,支持的功能也很多,同時也是可編程的,不過其中包含的內(nèi)容非常繁雜、API 設計也不是非常優(yōu)雅,所以還是需要一些學習成本的,對于長時間使用 MySQL 的開發(fā)者肯定會有些不習慣。

 
 
 
 
  1. db.collection.updateMany( 
  2.    
  3.    
  4.    { 
  5.      upsert: 
  6.      writeConcern: 
  7.      collation:  
  8.    } 

查詢語言的復雜是因為 MongoDB 支持了很多的數(shù)據(jù)類型,同時每一條數(shù)據(jù)記錄也就是文檔有著非常復雜的結構,這點是從設計上就沒有辦法避免的,所以還需要使用 MongoDB 的開發(fā)者花一些時間去學習各種各樣的 API。

RDBMS 與 MongoDB

MongoDB 使用面向文檔的的數(shù)據(jù)模型,導致很多概念都與 RDBMS 有一些差別,雖然從總體上來看兩者都有相對應的概念,不過概念之間細微的差別其實也會影響我們對 MongoDB 的理解:

傳統(tǒng)的 RDBMS 其實使用 Table 的格式將數(shù)據(jù)邏輯地存儲在一張二維的表中,其中不包括任何復雜的數(shù)據(jù)結構,但是由于 MongoDB 支持嵌入文檔、數(shù)組和哈希等多種復雜數(shù)據(jù)結構的使用,所以它最終將所有的數(shù)據(jù)以 BSON 的數(shù)據(jù)格式存儲起來。

RDBMS 和 MongoDB 中的概念都有著相互對應的關系,數(shù)據(jù)庫、表、行和索引的概念在兩中數(shù)據(jù)庫中都非常相似,唯獨***的 JOIN 和 Embedded Document 或者 Reference 有著巨大的差別。這一點差別其實也影響了在使用 MongoDB 時對集合(Collection)Schema 的設計,如果我們在 MongoDB 中遵循了與 RDBMS 中相同的思想對 Collection 進行設計,那么就不可避免的使用很多的 "JOIN" 語句,而 MongoDB 是不支持 "JOIN" 的,在應用內(nèi)做這種查詢的性能非常非常差,在這時使用嵌入式的文檔其實就可以解決這種問題了,嵌入式的文檔雖然可能會造成很多的數(shù)據(jù)冗余導致我們在更新時會很痛苦,但是查詢時確實非常迅速。

 
 
 
 
  1.   _id: 
  2.   name: "draveness", 
  3.   books: [ 
  4.     { 
  5.       _id: 
  6.       name: "MongoDB: The Definitive Guide" 
  7.     }, 
  8.     { 
  9.       _id: 
  10.       name: "High Performance MySQL" 
  11.     } 
  12.   ] 

在 MongoDB 的使用時,我們一定要忘記很多 RDBMS 中對于表設計的規(guī)則,同時想清楚 MongoDB 的優(yōu)勢,仔細思考如何對表進行設計才能利用 MongoDB 提供的諸多特性提升查詢的效率。

數(shù)據(jù)模型

MongoDB 與 RDBMS 之間***的不同,就是數(shù)據(jù)模型的設計有著非常明顯的差異,數(shù)據(jù)模型的不同決定了它有著非常不同的特性,存儲在 MongoDB 中的數(shù)據(jù)有著非常靈活的 Schema,我們不需要像 RDBMS 一樣,在插入數(shù)據(jù)之前就決定并且定義表中的數(shù)據(jù)結構,MongoDB 的結合不對 Collection 的數(shù)據(jù)結構進行任何限制,但是在實際使用中,同一個 Collection 中的大多數(shù)文檔都具有類似的結構。

在為 MongoDB 應用設計數(shù)據(jù)模型時,如何表示數(shù)據(jù)模型之間的關系其實是需要開發(fā)者需要仔細考慮的,MongoDB 為表示文檔之間的關系提供了兩種不同的方法:引用和嵌入。

標準化數(shù)據(jù)模型

引用(Reference)在 MongoDB 中被稱為標準化的數(shù)據(jù)模型,它與 MySQL 的外鍵非常相似,每一個文檔都可以通過一個 xx_id 的字段『鏈接』到其他的文檔:

但是 MongoDB 中的這種引用不像 MySQL 中可以直接通過 JOIN 進行查找,我們需要使用額外的查詢找到該引用對應的模型,這雖然提供了更多的靈活性,不過由于增加了客戶端和 MongoDB 之間的交互次數(shù)(Round-Trip)也會導致查詢變慢,甚至非常嚴重的性能問題。

MongoDB 中的引用并不會對引用對應的數(shù)據(jù)模型是否真正存在做出任何的約束,所以如果在應用層級沒有對文檔之間的關系有所約束,那么就可能會出現(xiàn)引用了指向不存在的文檔的問題:

雖然引用有著比較嚴重的性能問題并且在數(shù)據(jù)庫層面沒有對模型是否被刪除加上限制,不過它提供的一些特點是嵌入式的文檔無法給予了,當我們需要表示多對多關系或者更加龐大的數(shù)據(jù)集時,就可以考慮使用標準化的數(shù)據(jù)模型 — 引用了。

嵌入式數(shù)據(jù)模型

除了與 MySQL 中非常相似的引用,MongoDB 由于其獨特的數(shù)據(jù)存儲方式,還提供了嵌入式的數(shù)據(jù)模型,嵌入式的數(shù)據(jù)模型也被認為是不標準的數(shù)據(jù)模型:

因為 MongoDB 使用 BSON 的數(shù)據(jù)格式對數(shù)據(jù)進行存儲,而嵌入式數(shù)據(jù)模型中的子文檔其實就是父文檔中的另一個值,只是其中存儲的是一個對象:

 
 
 
 
  1.   _id: 
  2.   username: "draveness", 
  3.   age: 20, 
  4.   contact: [ 
  5.     { 
  6.       _id: 
  7.       email: "i@draveness.me" 
  8.     } 
  9.   ] 

嵌入式的數(shù)據(jù)模型允許我們將有相同的關系的信息存儲在同一個數(shù)據(jù)記錄中,這樣應用就可以更快地對相關的數(shù)據(jù)進行查詢和更新了;當我們的數(shù)據(jù)模型中有『包含』這樣的關系或者模型經(jīng)常需要與其他模型一起出現(xiàn)(查詢)時,比如文章和評論,那么就可以考慮使用嵌入式的關系對數(shù)據(jù)模型進行設計。

總而言之,嵌入的使用讓我們在更少的請求中獲得更多的相關數(shù)據(jù),能夠為讀操作提供更高的性能,也為在同一個寫請求中同時更新相關數(shù)據(jù)提供了支持。

MongoDB 底層的 WiredTiger 存儲引擎能夠保證對于同一個文檔的操作都是原子的,任意一個寫操作都不能原子性地影響多個文檔或者多個集合。

主鍵和索引

在這一節(jié)中,我們將主要介紹 MongoDB 中不同類型的索引,當然也包括每個文檔中非常重要的字段 _id ,可以 理解 為 MongoDB 的『主鍵』,除此之外還會介紹單字段索引、復合索引以及多鍵索引等類型的索引。

MongoDB 中索引的概念其實與 MySQL 中的索引相差不多,無論是底層的數(shù)據(jù)結構還是基本的索引類型都幾乎完全相同,兩者之間的區(qū)別就在于因為 MongoDB 支持了不同類型的數(shù)據(jù)結構,所以也理所應當?shù)靥峁┝烁嗟乃饕N類。

默認索引

MySQL 中的每一個數(shù)據(jù)行都具有一個主鍵,數(shù)據(jù)庫中的數(shù)據(jù)都是按照以主鍵作為鍵物理地存儲在文件中的;除了用于數(shù)據(jù)的存儲,主鍵由于其特性也能夠加速數(shù)據(jù)庫的查詢語句。

而 MongoDB 中所有的文檔也都有一個唯一的 _id 字段,在默認情況下所有的文檔都使用一個長 12 字節(jié)的 ObjectId 作為默認索引:

前四位代表當前 _id 生成時的 Unix 時間戳,在這之后是三位的機器標識符和兩位的處理器標識符,***是一個三位的計數(shù)器,初始值就是一個隨機數(shù);通過這種方式代替遞增的 id 能夠解決分布式的 MongoDB 生成唯一標識符的問題,同時可以在一定程度上保證 id 的的增長是遞增的。

單字段索引(Single Field)

除了 MongoDB 提供的默認 _id 字段之外,我們還可以建立其它的單鍵索引,而且其中不止支持順序的索引,還支持對索引倒排:

 
 
 
 
  1. db.users.createIndex( { age: -1 } ) 

MySQL8.0 之前的索引都只能是正序排列的,在 8.0 之后才引入了逆序的索引,單一字段索引可以說是 MySQL 中的輔助(Secondary)索引的一個子集,它只是對除了 _id 外的任意單一字段建立起正序或者逆序的索引樹。

復合索引(Compound)

除了單一字段索引這種非常簡單的索引類型之外,MongoDB 還支持多個不同字段組成的復合索引(Compound Index),由于 MongoDB 中支持對同一字段的正逆序排列,所以相比于 MySQL 中的輔助索引就會出現(xiàn)更多的情況:

 
 
 
 
  1. db.users.createIndex( { username: 1, age: -1 } )  
  2. db.users.createIndex( { username: 1, age: 1 } ) 

上面的兩個索引是完全不同的,在磁盤上的 B+ 樹其實也按照了完全不同的順序進行存儲,雖然 username 字段都是升序排列的,但是對于 age 來說,兩個索引的處理是完全相反的:

這也就造成了在使用查詢語句對集合中數(shù)據(jù)進行查找時,如果約定了正逆序,那么其實是會使用不同的索引的,所以在索引創(chuàng)建時一定要考慮好使用的場景,避免創(chuàng)建無用的索引。

多鍵索引(Multikey)

由于 MongoDB 支持了類似數(shù)組的數(shù)據(jù)結構,所以也提供了名為多鍵索引的功能,可以將數(shù)組中的每一個元素進行索引,索引的創(chuàng)建其實與單字段索引沒有太多的區(qū)別:

 
 
 
 
  1. db.collection.createIndex( { address: 1 } ) 

如果一個字段是值是數(shù)組,那么在使用上述代碼時會自動為這個字段創(chuàng)建一個多鍵索引,能夠加速對數(shù)組中元素的查找。

文本索引(Text)

文本索引是 MongoDB 為我們提供的另一個比較實用的功能,不過在這里也只是對這種類型的索引提一下,也不打算深入去談談這東西的性能如何,如果真的要做全文索引的話,還是推薦使用 Elasticsearch 這種更專業(yè)的東西來做,而不是使用 MongoDB 提供的這項功能。

存儲

如何存儲數(shù)據(jù)就是一個比較重要的問題,在前面我們已經(jīng)提到了 MongoDB 與 MySQL 一樣都提供了插件化的存儲引擎支持,作為 MongoDB 的主要組件之一,存儲引擎全權負責了 MongoDB 對數(shù)據(jù)的管理。

WiredTiger

MongoDB3.2 之后 WiredTiger 就是默認的存儲引擎了,如果對各個存儲引擎并不了解,那么還是不要改變 MongoDB 的默認存儲引擎;它有著非常多的優(yōu)點,比如擁有效率非常高的緩存機制:

WiredTiger 還支持在內(nèi)存中和磁盤上對索引進行壓縮,在壓縮時也使用了前綴壓縮的方式以減少 RAM 的使用,在后面的文章中我們會詳細介紹和分析 WiredTiger 存儲引擎是如何對各種數(shù)據(jù)進行存儲的。

Journaling

為了在數(shù)據(jù)庫宕機保證 MongoDB 中數(shù)據(jù)的持久性,MongoDB 使用了 Write Ahead Logging 向磁盤上的 journal 文件預先進行寫入;除了 journal 日志,MongoDB 還使用檢查點(Checkpoint)來保證數(shù)據(jù)的一致性,當數(shù)據(jù)庫發(fā)生宕機時,我們就需要 Checkpoint 和 journal 文件協(xié)作完成數(shù)據(jù)的恢復工作:

  • 在數(shù)據(jù)文件中查找上一個檢查點的標識符;
  • 在 journal 文件中查找標識符對應的記錄;
  • 重做對應記錄之后的全部操作;

MongoDB 會每隔 60s 或者在 journal 數(shù)據(jù)的寫入達到 2GB 時設置一次檢查點,當然我們也可以通過在寫入時傳入 j: true 的參數(shù)強制 journal 文件的同步。

這篇文章并不會介紹 Journal 文件的格式以及相關的內(nèi)容,作者可能會在之后介紹分析 WiredTiger 的文章中簡單分析其存儲格式以及一些其它特性。

總結

這篇文章中只是對 MongoDB 的一些基本特性以及數(shù)據(jù)模型做了簡單的介紹,雖然『***』擴展是 MongoDB 非常重要的特性,但是由于篇幅所限,我們并沒有介紹任何跟 MongoDB 集群相關的信息,不過會在之后的文章中專門介紹多實例的 MongoDB 是如何協(xié)同工作的。

在這里,我想說的是,如果各位讀者接收到了類似 MongoDB 比 MySQL 性能好很多的斷言,但是在使用 MongoDB 的過程中仍然遵循以往 RDBMS 對數(shù)據(jù)庫的設計方式,那么我相信性能在最終也不會有太大的提升,反而可能會不升反降;只有真正理解 MongoDB 的數(shù)據(jù)模型,并且根據(jù)業(yè)務的需要進行設計才能很好地利用類似嵌入式文檔等特性并提升 MongoDB 的性能。


文章名稱:[淺入淺出]MongoDB和WiredTiger
鏈接URL:http://www.5511xx.com/article/dppdhco.html