DolphinDB和MongoDB都是爲大數據而生的數據庫。可是二者有這較大的區別。前者是列式存儲的多模型數據庫,主要用於結構化時序數據的高速存儲、查詢和分析。後者是文檔型的NoSQL數據庫,可用於處理非結構化和結構化的數據,能夠根據鍵值快速查找或寫入一個文檔。MongoDB有着本身最合適的應用場景。可是市場上缺乏優秀的大數據產品,很多用戶試圖使用MongoDB來存儲和查詢物聯網和金融領域的結構化時序數據。本測試的目的是評估MongoDB是否適合此類海量時序數據集。css
本次測試在單機上進行,測試設備配置以下:node
主機:DELL OptiPlex 7060linux
CPU:Intel(R) Core(TM) i7-8700 CPU@3.20GHZ,6核12線程git
內存:32 GB (8GB x 4, 2,666 MHz)github
硬盤: 2T HDD (222MB/s讀取;210MB/s寫入)算法
OS:Ubuntu 18.04 LTSsql
DolphinDB選用Linux0.89做爲測試版本,全部節點最大鏈接數爲128,數據副本設置爲2,設置1個控制節點,1個代理節點,3個數據節點。mongodb
MongoDB選用Linux4.0.5社區版做爲測試版本,shard集羣線程數爲12,全部服務器的最大鏈接數均爲128。MongoDB的shard集羣設置爲1個config服務器,1個mongos路由服務器,3個分片服務器,其中config服務器設置爲有1個主節點和2個從節點的replica集羣,3個分片服務器均設置爲有1個主節點,1個從節點,1個仲裁節點的replica集羣。DolphinDB和MongoDB的參數配置請參考附錄1。數據庫
本報告測試了DolphinDB database和MongoDB在小數據量級(4.2GB)和大數據量級(62.4GB)下的性能。緩存
對於大小兩種數據集,咱們測試兩種數據庫在磁盤分區狀況下的性能,查詢時間均包含了磁盤IO的時間。爲了保證測試的公平,咱們在測試前經過linux命令:sync,echo1,2,3 | tee /proc/sys/vm/drop_caches清空頁面緩存,目錄緩存和硬盤緩存,隨後依次執行13條查詢,並記錄執行的時間。
如下是兩個數據集的表結構和分區方法:
設備傳感器信息小數據集(CSV文件,4.2G, 3千萬條數據)
咱們選用TimescaleDB官網提供的devices_readings_big.csv(如下簡稱readings數據集)和device_info_big.csv(如下簡稱info數據集)設備傳感器數據做爲小數據測試集。readings數據集包含3,000個設備在10,000個時間間隔(2016.11.15-2016.11.19)上的傳感器信息,包括傳感器時間,設備ID,電池,內存,CPU等時序統計信息。info數據集包括3,000個設備的設備ID,版本號,製造商,模式和操做系統等統計信息。
數據來源:https://docs.timescale.com/v1.1/tutorials/other-sample-datasets
數據集共3千萬 條數據(4.2G),壓縮包內包含一張設備信息表和一張設備傳感器信息記錄表,表結構以及分區方式以下:
readings數據集
info數據集
數據集中device_id這一字段有3000個不一樣的值,且在readings數據集中重複出現,這種狀況下使用string類型不只佔用大量空間並且查詢效率低,DolphinDB的symbol類型能夠很好地解決佔用空間和效率兩個問題。
咱們在 DolphinDB database 中採用組合分區,將time字段做爲分區的第一個維度,按天分爲 4 個區,再將device_id做爲分區的第二個維度,天天一共分 10 個區,最後每一個分區所包含的原始數據大小約爲100MB。
咱們在MongoDB中一樣採用組合分區的方式,將time做爲分區的第一維度,根據日期進行範圍分區,再將設備ID做爲第二分區維度,根據設備ID進行範圍分區。MongoDB的範圍分區是根據塊的大小進行分區的,當數據塊大小大於某個閾值,數據庫會自動將一個大的數據塊分爲兩個小的數據塊,實現分區。通過測試,咱們發現當chunkSize(數據塊分區閾值)爲1024時,性能最佳。最終,readings數據集總共分爲17個分區。
MongoDB要求分區字段必須創建索引,所以咱們創建日期+設備ID的複合索引,複合索引能夠加快查詢速度,可是MongoDB在創建索引時會消耗時間和空間。readings數據集分區創建time_1_device_id_1增序索引耗時爲5分鐘,佔用空間大小爲1.1G。創建索引的腳本以下所示:
use device_ptdb.device_readings.createIndex({time:1,device_id:1}
股票交易大數據集(CSV文件,62.4G,16億條數據)
咱們選用紐約證券交易所(NYSE)提供的2007.08.07-2007.08.10四天的股市Level1報價數據(如下簡稱TAQ數據集)做爲大數據測試集,數據集包含8,000多支股票在4天內的交易時間,股票代碼,買入價,賣出價,買入量,賣出量等報價信息。
數據集有4個csv文件,每一個文件在14G到17G之間,總共大小爲62.4G,大約16億條數據,每一個CSV文件保存一個交易日的交易信息,數據來源於(https://www.nyse.com/market-data/historical)。TAQ數據集結構以下所示:
在DolphinDB中,咱們採用組合分區,將date字段做爲分區的第一維度,天天一個分區,共四個分區,再將symbol字段做爲分區的第二維度,根據範圍分區,天天分爲100個分區。最後總共分爲400個分區,每一個分區大約40MB。
在MongoDB中一樣採用組合分區方式,分區維度與DolphinDB相同,將chunkSize設置爲1024,總共分爲385個分區。
MongoDB在對TAQ數據集分區時創建date_1_symbol_1增序索引消耗的時間爲53分鐘,佔用空間大小爲19G,創建索引的腳本以下所示:
use taq_pt_dbdb.taq_pt_col.createIndex({date:1,symbol:1}
3.1 導入性能
在DolphinDB中使用如下腳本導入:
timer { for (fp in fps) { job_id_tmp = fp.strReplace(".csv", "") job_id_tmp1=split(job_id_tmp,"/") job_id=job_id_tmp1[6] job_name = job_id submitJob(job_id, job_name, loadTextEx{db, `taq, `date`symbol, fp}) print now() + ": 已導入 " + fp } getRecentJobs(size(fps))}
在MongoDB導入TAQ數據集時,爲了加快導入速度,將63G的數據分爲16個小文件導入,每一個文件大小在3.5G~4.4G之間,而後使用如下腳本導入:
for f in /media/xllu/aa/TAQ/mongo_split/*.csv ; do /usr/bin/mongoimport \ -h localhost \ --port 40000 \ -d taq_pt_db \ -c taq_pt_col \ --type csv \ --columnsHaveTypes \ --fields "symbol.string(),date.date(20060102),time.date(15:04:05),bid.double(),ofr.double(),bidsiz.int32(),ofrsiz.int32(),mode.int32(),ex.string(),mmid.string()" \ --parseGrace skipRow \ --numInsertionWorkers 12 \ --file $f echo "文件 $f 導入完成"done
導入性能以下表所示:
從上表可得,DolphinDB在導入結構化的時序數據時,速度遠快於MongoDB,下面從幾個方面分析導入結果。
(1)橫向比較
因爲兩個數據集的字段數量和字段類型不同,readings數據集多爲字符串類型,TAQ數據集多爲數值類型,相比於字符串類型,數值類型導入更快,所以能夠看到MongoDB和DolphinDB在導入TAQ數據集時,速率更快。
(2)縱向比較
MongoDB屬於文檔型數據庫,導入速度受文檔數量的影響很大,能夠看出導入3千萬條記錄大約需1小時,導入16億條記錄大約需55小時,記錄條數相差大約53倍,導入時間相差約55倍,考慮到每條記錄字段類型和數據的影響,能夠認爲導入速度和記錄條數大約成正比。
DolphinDB屬於列式數據庫,存儲這種結構化的數據時,DolphinDB會將一個字段當成一個列,存儲在一個列文件中。導入readings數據集時建立了12個列文件,導入TAQ數據集時,建立了10個列文件,列文件數量相差很少。導入4.2G數據,須要63秒,導入62.4G數據,須要11分30秒。數據集大小相差大約14.8倍,導入時間相差大約11倍,考慮到列文件數量和存儲類型的不一樣,能夠認爲導入時間和文件大小大約成正比。
DolphinDB在導入時序結構化數據時,在列字段類型和數量相差不大的狀況下,導入時間和文件大小成正相關,符合列式存儲數據庫的特色。MongoDB在導入時序結構化數據時,在字段相差不大的狀況下,導入時間和記錄條數成正相關,符合文檔型存儲數據庫的特色。
(3)MongoDB導入相對緩慢的緣由分析
DolphinDB採用列式存儲,效率遠遠高於MongoDB的文檔型存儲。MongoDB按照記錄逐條導入,在記錄條數很大的狀況下,MongoDB數據導入時長增長,性能降低。
MongoDB在sharding集羣配置時,必須開啓journaling日誌,先寫入記錄再進行導入操做,下降了其導入速度。
由於MongoDB屬於NoSQL數據庫,其沒有主鍵概念,爲了保證惟一性約束,數據在導入時必須建立一個數據庫自動生成的惟一索引來表徵每一條記錄,數據導入和索引必須同時進行,所以下降了導入速度。
3.2 導出性能
在DolphinDB中使用如下腳本進行數據導出:
timer saveText((select * from t),"/media/xllu/aa/device/device_readings_out.csv")
在MongoDB中使用如下腳本進行數據導出:
mongoexport -h localhost:40000 -d db_nopt -c device_readings -o /media/xllu/aa/device/device_readings_mongo_out.csv
小數據集導出性能以下表所示:
數據庫磁盤空間佔用性能對比主要對比DolphinDB和MongoDB數據庫導入readings數據集和TAQ數據集這兩種大小的數據集後,在分區狀況下各數據庫中的數據所佔磁盤空間的大小。磁盤佔用指標爲數據在磁盤中的大小。
DolphinDB直接經過讀取全部列式數據文件的大小獲取,MongoDB經過db.stats()得到數據存儲的大小。兩個數據庫均有一個備份,MongoDB中數據存儲大小還包括索引的大小。測試結果以下表所示:
相同數據量,MongoDB的磁盤佔用空間大約是DolphinDB的2~3倍,主要有如下緣由:
(1)DolphinDB採用列式存儲方式,每一個列有固定的類型,經過LZ4壓縮算法,將每一個字段按照類型壓縮存儲爲一個列文件。而且針對symbol類型,還採用位圖壓縮算法解決存儲空間佔用的問題,進一步提升了壓縮率。MongoDB本次測試採用的是WiredTiger存儲引擎,選用snappy壓縮算法。
(2)MongoDB中創建分區數據庫均要對分區字段創建索引,進一步致使其存儲空間變大,經分析發現,readings數據集對time和device_id字段創建的索引大小爲1.1G,TAQ數據集對date和symbol字段創建的索引大小爲19G。
對於readings數據集和TAQ數據集,咱們對比了如下8種經常使用的SQL查詢。
一、點查詢:根據某一字段的具體值進行查詢。
二、範圍查詢:根據一個或者多個字段的範圍根據時間區間進行查詢。
三、聚合查詢:根據數據庫提供的針對字段列進行計數,平均值,求和,最大值,最小值,標準差等聚合函數進行查詢。
四、精度查詢:根據不一樣標籤維度列進行數據聚合,實現高維或者低維的字段範圍查詢,測試有hour精度,minute精度。
五、關聯查詢:根據不一樣的字段,在進行相同精度,相同的時間範圍內進行過濾查詢的基礎上,篩選出有關聯關係的指標列並進行分組。
六、對比查詢:根據兩個維度將表中某字段的內容從新整理爲一張表格(第一維度做爲列,第二維度做爲行)
七、抽樣查詢:根據數據庫提供的數據採樣API,能夠爲每一次查詢手動指定採樣方式進行數據的稀疏處理,防止查詢時間範圍太大數據量過載的問題。
八、經典查詢:實際業務中經常使用的查詢。
執行時間是以毫秒爲單位的。爲了消除網絡傳輸等不穩定因素的影響,查詢性能比較的時間指標爲服務器執行某個查詢的時間,不包括結果傳輸和顯示的時間。
4.2G設備傳感器信息小數據集查詢測試
對於小數據集的測試,咱們均測試磁盤分區數據,執行時間包括了磁盤IO的時間。爲了保證測試的準確性和公正性,每次啓動測試前均經過Linux系統命令sync;echo 1,2,3 | tee /proc/sys/vm/drop_caches清除系統的頁面緩存,目錄項緩存和硬盤緩存,啓動程序後一次執行樣例一遍,並記錄執行的時間。
DolphinDB中使用如下腳本獲得數據庫句柄:
dp_readings = "dfs://db_range_dfs"device_readings=loadTable(dp_readings, `readings_pt)
MongoDB中執行use device_pt語句切換數據庫至device_pt數據庫。在執行關聯查詢時,因爲info數據集的數據量較小,所以能夠把數據加載到內存中。在MongoDB中執行db.device_info.find({})將3,000條設備記錄所有加載,在DolphinDB中執行loadText(dp_info)將3,000條設備記錄加載至內存。在DolphinDB中使用timer計算查詢執行耗時,在MongoDB中使用explain()函數獲取執行時間。下面是DolphinDB在小數據集上的查詢腳本,MongoDB的查詢腳本見附錄。
查詢性能以下表所示:
對於範圍查詢,在包括了分區字段的查詢中,如查詢3,4所示,MongoDB能夠調用複合索引,DolphinDB能夠經過分區字段加快查詢,這種狀況下兩個數據庫的差距在4倍以內,並非很大。在包括了未分區字段的查詢中,如查詢5所示,MongoDB無法調用未分區字段的索引,須要進行全字段搜索過濾,DolphinDB則無需搜索不在where過濾條件中的字段,這種狀況下DolphinDB和MongoDB的差距進一步擴大。能夠看出在處理這種結構化時序數據時, DolphinDB採起的列式存儲的方式的效率比MongoDB創建索引的方式更加高效,也更加適用於多維結構化數據的查詢。
對於點查詢,在查詢1中,MongoDB在創建有time+device_id索引的狀況下能夠快速的找到某個時間點的記錄,DolphinDB中按照日期分爲4天,查找某一天的具體的時間點須要選定一個分區再進行檢索,這種狀況下DolphinDB比MongoDB慢。在查詢2中,MongoDB的過濾字段僅爲設備ID,沒有包括time字段,咱們從explain()中發現查詢過程當中沒有調用複合索引,這是由於查詢字段必須包括複合索引的首字段,索引纔會起做用,查詢1僅僅根據設備ID過濾,不涉及time字段的過濾, MongoDB不會調用複合索引,所以這種狀況下,DolphinDB比MongoDB快。
對於關聯查詢,MongoDB做爲NoSQL數據庫,僅支持左外鏈接,而且由於其沒有關係型數據庫的主鍵約束,要實現錶鏈接查詢只能使用內嵌文檔的方式,這種方式並不利於計算和聚合。DolphinDB做爲關係型數據,其支持等值鏈接,左鏈接,全鏈接,asof鏈接,窗口鏈接和交叉鏈接,錶鏈接查詢功能豐富,能夠高效方便地處理海量結構化時序數據。從查詢9~10中咱們能夠看出DolphinDB快於MongoDB,而且關聯查詢越複雜,性能差距越大。
對於抽樣查詢,MongoDB能夠在aggregation函數中經過sample語句實現抽樣查詢,抽樣方式取決於集合的大小,N(抽樣數)的大小和sample語句實現抽樣查詢,抽樣方式取決於集合的大小,N(抽樣數)的大小和sample語句在pipeline中的位置。DolphinDB不支持全表抽樣,僅支持分區字段抽樣。由於兩種數據抽樣查詢的實現過程差異較大,因此不作比較。
對於插值查詢,MongoDB並無內置的函數能夠實現插值查詢,而 DolphinDB 支持 4 種插值方式,ffill 向後取非空值填充、bfill 向前去非空值填充、lfill 線性插值、nullFill 指定值填充。
對於對比查詢,MongoDB做爲文檔型數據庫,其存儲單元是文檔,集合中包含若干文檔,文檔採用BSON格式,沒有行和列的概念,所以沒法實現選擇兩個維度將表中某字段的內容整理爲一張表(第一個維度做爲列,第二個維度做爲行)的功能。DolphinDB中內置有pivot by函數語句,選定分類的維度能夠方便的將制定內容整理爲一張表。由於MongoDB不支持對比查詢,因此不作比較。
62.4G股票交易大數據集查詢測試
DolphinDB中使用如下腳本獲得數據庫句柄:
taq_pt_db= "dfs://db_compound_dfs"taq_pt_col=loadTable(taq_pt_db, `readings_pt)
MongoDB中執行use taq_pt_db語句切換數據庫至taq_pt_db數據庫。
大數據集DolphinDB的查詢腳本以下所示:
查詢性能以下表所示:
在大數據量,兩個數據庫均作了分區的狀況下,DolphinDB依然比MongoDB大約快5-20倍。查詢1是根據日期,股票代碼進行的點查詢,這種狀況下MongoDB和DolphinDB的性能差距不大,DolphinDB略慢於MongoDB,這是MongoDB進行復合分區時會創建date+symbol複合索引能夠較爲快速的找到結果,是MongoDB比較好的應用場景,可是對比查詢5~9可知,MongoDB的計算性能仍不如DolphinDB,差距大約在10-20倍之間。
時間序列數據庫DolphinDB和MongoDB在時序數據庫集上的對比測試,主要結論以下:
在處理結構化的時序數據時,不管是數據導入導出、磁盤空間佔用仍是查詢速度,DolphinDB的性能都比MongoDB更加優越。可是,MongoDB做爲文檔型的NoSQL數據庫,在數據模型多變的場景下以及處理非結構化數據方面更有優點。
1. DolphinDB環境配置
2. MongoDB環境配置
3. DolphinDB分區腳本
4. MongoDB分區腳本
5. MongoDB查詢腳本