DolphinDB和MongoDB都是為大數據而生的資料庫。但是兩者有這較大的區別。前者是列式存儲的多模型資料庫,主要用於結構化時序數據的高速存儲、查詢和分析。後者是文檔型的NoSQL資料庫,可用於處理非結構化和結構化的數據,可以根據鍵值快速查找或寫入一個文檔。MongoDB有著自己最合適的應用場景。但是市場上缺少優秀的大數據產品,不少用戶試圖使用MongoDB來存儲和查詢物聯網和金融領域的結構化時序數據。本測試的目的是評估MongoDB是否適合此類海量時序數據集。

時間序列資料庫DolphinDB和MongoDB在時序資料庫集上的對比測試,主要結論如下:

  • DolphinDB的數據導入速度比MongoDB高出兩個數量級。數據量越大,性能差距越明顯。數據導出方面,DolphinDB比MongoDB快50倍左右。
  • 磁碟空間佔用方面,MongoDB佔用磁碟是DolphinDB的2~3倍。
  • 資料庫查詢性能方面,DolphinDB在4個查詢性能測試中速度比MongoDB快30倍;在5個查詢性能測試中速度比MongoDB快10~30倍;在12個查詢性能測試中速度比MongoDB快數倍;僅在兩個點查詢測試中,DolphinDB慢於MongoDB。

1. 測試環境

本次測試在單機上進行,測試設備配置如下:

主機:DELL OptiPlex 7060

CPU:Intel(R) Core(TM) i7-8700 [email protected],6核12線程

內存:32 GB (8GB x 4, 2,666 MHz)

硬碟: 2T HDD (222MB/s讀取;210MB/s寫入)

OS:Ubuntu 18.04 LTS

DolphinDB選用Linux0.89作為測試版本,所有節點最大連接數為128,數據副本設置為2,設置1個控制節點,1個代理節點,3個數據節點。

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。

2. 數據集

本報告測試了DolphinDB和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,版本號,製造商,模式和操作系統等統計信息。

數據來源:docs.timescale.com/v1.1

數據集共3千萬 條數據(4.2G),壓縮包內包含一張設備信息表和一張設備感測器信息記錄表,表結構以及分區方式如下:

readings數據集

info數據集

數據集中device_id這一欄位有3000個不同的值,且在readings數據集中重複出現,這種情況下使用string類型不僅佔用大量空間而且查詢效率低,DolphinDB的symbol類型可以很好地解決佔用空間和效率兩個問題。

我們在 DolphinDB 中採用組合分區,將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_pt
db.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文件保存一個交易日的交易信息,數據來源於(nyse.com/market-data/hi)。TAQ數據集結構如下所示:

在DolphinDB中,我們採用組合分區,將date欄位作為分區的第一維度,每天一個分區,共四個分區,再將symbol欄位作為分區的第二維度,根據範圍分區,每天分為100個分區。最後總共分為400個分區,每個分區大約40MB。

在MongoDB中同樣採用組合分區方式,分區維度與DolphinDB相同,將chunkSize設置為1024,總共分為385個分區。

MongoDB在對TAQ數據集分區時建立date_1_symbol_1增序索引消耗的時間為53分鐘,佔用空間大小為19G,建立索引的腳本如下所示:

use taq_pt_db
db.taq_pt_col.createIndex({date:1,symbol:1}

3. 資料庫導入導出性能對比

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

小數據集導出性能如下表所示:

4. 資料庫磁碟空間佔用對比

資料庫磁碟空間佔用性能對比主要對比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。

5. 資料庫查詢性能

對於readings數據集和TAQ數據集,我們對比了以下8種常用的SQL查詢。

1、點查詢:根據某一欄位的具體值進行查詢。

2、範圍查詢:根據一個或者多個欄位的範圍根據時間區間進行查詢。

3、聚合查詢:根據資料庫提供的針對欄位列進行計數,平均值,求和,最大值,最小值,標準差等聚合函數進行查詢。

4、精度查詢:根據不同標籤維度列進行數據聚合,實現高維或者低維的欄位範圍查詢,測試有hour精度,minute精度。

5、關聯查詢:根據不同的欄位,在進行相同精度,相同的時間範圍內進行過濾查詢的基礎上,篩選出有關聯關係的指標列並進行分組。

6、對比查詢:根據兩個維度將表中某欄位的內容重新整理為一張表格(第一維度作為列,第二維度作為行)

7、抽樣查詢:根據資料庫提供的數據採樣API,可以為每一次查詢手動指定採樣方式進行數據的稀疏處理,防止查詢時間範圍太大數據量過載的問題。

8、經典查詢:實際業務中常用的查詢。

執行時間是以毫秒為單位的。為了消除網路傳輸等不穩定因素的影響,查詢性能比較的時間指標為伺服器執行某個查詢的時間,不包括結果傳輸和顯示的時間。

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語句在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倍之間。

6. 小結

在處理結構化的時序數據時,無論是數據導入導出、磁碟空間佔用還是查詢速度,DolphinDB的性能都比MongoDB更加優越。但是,MongoDB作為文檔型的NoSQL資料庫,在數據模型多變的場景下以及處理非結構化數據方面更有優勢。

附錄

1. DolphinDB環境配置

  • controller.cfg
  • agent.cfg
  • cluster.cfg
  • cluster.nodes

2. MongoDB環境配置

  • 分片伺服器配置:
    • 主節點:master_shard.txt
    • 從節點:slave_shard.txt
    • 仲裁節點:arbiter_shard.txt
  • 路由伺服器配置:master_mongos.txt
  • 配置伺服器:
    • 主節點:master_config.txt
    • 從節點:slave_config.txt
    • 仲裁節點:arbiter_config.txt

3. DolphinDB分區腳本

  • readings分區腳本
  • TAQ分區腳本

4. MongoDB分區腳本

  • readings分區腳本
  • TAQ分區腳本

5. MongoDB查詢腳本

  • readings查詢腳本
  • TAQ查詢腳本

推薦閱讀:

相关文章