值得注意的是,MongoDB既不支持JOIN(鏈接)也不支持transaction(事務)。Significantly, MongoDB supports neither joins nor transactions.mongodb
可是請注意MongDB有着大量其餘優良的特性,如二級索引、功能豐富的查詢語言以及對每個單個文檔文件的原子寫保證以及徹底一致性的讀取。數據庫
1、存儲引擎(Storage)緩存
mongodb 3.0默認存儲引擎爲MMAPV1,還有一個新引擎wiredTiger可選,或許能夠提升必定的性能。安全
mongodb中有多個databases,每一個database能夠建立多個collections,collection是底層數據分區(partition)的單位,每一個collection都有多個底層的數據文件組成。(參見下文data files存儲原理)多線程
wiredTiger引擎:3.0新增引擎,官方宣稱在read、insert和複雜的update下具備更高的性能。因此後續版本,咱們建議使用wiredTiger。全部的write請求都基於「文檔級別」的lock,所以多個客戶端能夠同時更新一個colleciton中的不一樣文檔,這種更細顆粒度的lock,能夠支撐更高的讀寫負載和併發量。由於對於production環境,更多的CPU能夠有效提高wireTiger的性能,由於它是的IO是多線程的。wiredTiger不像MMAPV1引擎那樣儘量的耗盡內存,它能夠經過在配置文件中指定「cacheSizeGB」參數設定引擎使用的內存量,此內存用於緩存工做集數據(索引、namespace,未提交的write,query緩衝等)。併發
MMAPv1引擎:mongodb原生的存儲引擎,比較簡單,直接使用系統級的內存映射文件機制(memory mapped files),一直是mongodb的默認存儲引擎,對於insert、read和in-place update(update不致使文檔的size變大)性能較高;不過MMAPV1在lock的併發級別上,支持到collection級別,因此對於同一個collection同時只能有一個write操做執行,這一點相對於wiredTiger而言,在write併發性上就稍弱一些。對於production環境而言,較大的內存可使此引擎更加高效,有效減小「page fault」頻率,可是由於其併發級別的限制,多核CPU並不能使其受益。此引擎將不會使用到swap空間,可是對於wiredTiger而言須要必定的swap空間。(核心:對於大文件MAP操做,比較忌諱的就是在文件的中間修改數據,並且致使文件長度增加,這會涉及到索引引用的大面積調整)oracle
爲了確保數據的安全性,mongodb將全部的變動操做寫入journal並間歇性的持久到磁盤上,對於實際數據文件將延遲寫入,和wiredTiger同樣journal也是用於數據恢復。全部的記錄在磁盤上連續存儲,當一個document尺寸變大時,mongodb須要從新分配一個新的記錄(舊的record標記刪除,新的記record在文件尾部從新分配空間),這意味着mongodb同時還須要更新此文檔的索引(指向新的record的offset),與in-place update相比,將消耗更多的時間和存儲開支。因而可知,若是你的mongodb的使用場景中有大量的這種update,那麼或許MMAPv1引擎並不太適合,同時也反映出若是document沒有索引,是沒法保證document在read中的順序(即天然順序)。3.0以後,mongodb默認採用「Power of 2 Sized Allocations」,因此每一個document對應的record將有實際數據和一些padding組成,這padding能夠容許document的尺寸在update時適度的增加,以最小化從新分配record的可能性。此外從新分配空間,也會致使磁盤碎片(舊的record空間)。app
Power of 2 Sized Allocations:默認狀況下,MMAPv1中空間分配使用此策略,每一個document的size是2的次冪,好比3二、6四、12八、256...2MB,若是文檔尺寸大於2MB,則空間爲2MB的倍數(2M,4M,6M等)。這種策略有2種優點,首先那些刪除或者update變大而產生的磁盤碎片空間(尺寸變大,意味着開闢新空間存儲此document,舊的空間被mark爲deleted)能夠被其餘insert重用,再者padding能夠容許文檔尺寸有限度的增加,而無需每次update變大都從新分配空間。此外,mongodb還提供了一個可選的「No padding Allocation」策略(即按照實際數據尺寸分配空間),若是你確信數據絕大多數狀況下都是insert、in-place update,極少的delete,此策略將能夠有效的節約磁盤空間,看起來數據更加緊湊,磁盤利用率也更高。post
內存映射存儲引擎:MongoDB目前支持的存儲引擎爲內存映射引擎。當MongoDB啓動的時候,會將全部的數據文件映射到內存中,而後操做系統會託管全部的磁盤操做。性能
備註:mongodb 3.2+以後,默認的存儲引擎爲「wiredTiger」,大量優化了存儲性能,建議升級到3.2+版本。
摘自:http://shift-alt-ctrl.iteye.com/blog/2255580
數據文件
在MongoDB的數據文件夾中(默認路徑是/data/db)由構成數據庫的全部文件。每個數據庫都包含一個.ns文件和一些數據文件,其中數據文件會隨着數據量的增長而變多。因此若是有一個數據庫名字叫作foo,那麼構成foo這個數據庫的文件就會由foo.ns,foo.0,foo.1,foo.2等等組成。數據文件每新增一次,大小都會是上一個數據文件的2倍,每一個數據文件最大2G。這樣的設計有利於防止數據量較小的數據庫浪費過多的空間,同時又能保證數據量較大的數據庫有相應的空間使用。
MongoDB會使用預分配方式來保證寫入性能的穩定(這種方式可使用–noprealloc關閉)。預分配在後臺進行,而且每一個預分配的文件都用0進行填充。這會讓MongoDB始終保持額外的空間和空餘的數據文件,從而避免了數據增加過快而帶來的分配磁盤空間引發的阻塞。
『文件id + 文件內offset 』
插入新文檔時,MongoDB 會調用底層KV引擎存儲文檔內容,並生成一個 RecordId 的做爲文檔的位置信息標識,經過 RecordId 就能在底層KV引擎讀取到文檔的內容。
若是插入的集合包含索引(MongoDB的集合默認會有_id索引),針對每項索引,還會往底層KV引擎插入一個新的 key-value,key 是索引的字段內容,value 爲插入文檔時生成的 RecordId,這樣就能快速根據索引找到文檔的位置信息。
如上圖所示,集合包含{_id: 1}, {name: 1} 2個索引
有了上述的數據,在根據_id訪問時文檔時 (根據其餘索引字段相似)
摘自:https://toutiao.io/posts/9oxdop/preview