DolphinDB 分散式表資料更新原理和效能介紹

語言: CN / TW / HK

1. 概述

DolphinDB 從 1.30.6 版本開始支援更新分散式表資料。更新操作支援事務,具備事務 ACID 的特性,且通過 MVCC 實現快照隔離級別。DolphinDB 為多模資料庫,目前支援兩種儲存引擎: OLAP 和 TSDB (詳見 DolphinDB 資料模型),不同引擎的更新操作的原理和效能不同。

本文將分別介紹兩種儲存引擎的更新操作相關的原理,並通過實驗驗證和分析相關效能。

2. 使用方法

DolphinDB 提供 3 種更新分散式表的方法:

  • 標準 SQL 的 update 語法(注意,DolphinDB 僅支援關鍵字小寫);
  • sqlUpdate 方法,動態生成 SQL update 語句的元程式碼。生成元程式碼後,通過 eval 函式執行。具體用法見《DolphinDB教程:超程式設計》
  • upsert! 方法,若新資料的主鍵值已存在,更新該主鍵值的資料;否則新增資料。

下面通過一個簡單的例子介紹更新分散式表的 3 種方法:

  • 通過 update SQL 和 sqlUpdate 方法更新所有 ID=1 的行的 vol 列資料;
  • 通過 upsert! 更新第一個 ID=1 所在行的 date 和 vol 列資料。

(1)使用附件指令碼建庫表;

(2)更新資料:

方法1,下列 update SQL語句執行後,ID 為1的所有記錄的 vol 值更新為1:

update pt set vol = 1 where ID = 1

方法2,下列 sqlUpdate 語句執行後,ID 為1的所有記錄的 vol 值更新為2:

sqlUpdate(pt, <2 as vol>, where=<ID = 1>).eval()

方法3,下列 upsert! 語句執行後,第一個 ID=1 所在記錄的 date 更新為 2022.08.07,vol 更新為 3:

newData = table(1 as ID, 2022.08.07 as date, 3 as vol) 
upsert!(pt, newData, keyColNames=`ID)

3. 儲存機制簡介

在瞭解更新原理之前,需要先簡單瞭解 DolphinDB 的儲存機制。

DolphinDB 內建分散式檔案系統 DFS,由其統一管理各個節點的儲存空間,在對資料集進行分割時,可以全域性優化,規避資料分佈不均勻等問題。通過 DFS,我們可以將同一叢集中不同資料節點上的儲存資料夾組織起來,形成一個單獨的、邏輯的、層次式的共享檔案系統。更多分割槽資料庫介紹可以參考《DolphinDB教程:分割槽資料庫》

DolphinDB 提供配置項 volume,可以為每個節點指定資料檔案的儲存路徑,使用者可以通過 pnodeRun(getAllStorages) 查詢路徑。

3.1 OLAP 引擎儲存結構

在 OLAP 中,每個分割槽內部都會為表的每列資料分別儲存一個列檔案。例如第 2 節指令碼建立的使用 OLAP 引擎的表 pt,其分割槽 [0, 50) 的資料檔案儲存在 <volumes>/CHUNKS/db1/0_50/gA/pt_2 路徑下,其中:

  • db1 為庫名;
  • 0_50 為範圍分割槽 [0, 50);
  • gA 為表的物理名索引,於 1.30.16/2.00.4 版本為支援表級分割槽時引入;
  • pt_2 為 pt 表的版本資料夾,其中 “_2“ 指表在庫內的序號,於 1.30.1 版本支援 renameTable 特性時引入。

使用者可以進入庫名目錄,通過 tree 命令查看錶的資料檔案目錄結構,如下所示:

$ tree
.
├── 0_50
│   └── gA
│       └── pt_2
│           ├── date.col
│           ├── ID.col
│           └── vol.col
├── 50_100
│   └── gA
│       └── pt_2
│           ├── date.col
│           ├── ID.col
│           └── vol.col
├── dolphindb.lock
├── domain
└── pt.tbl

6 directories, 9 files

3.2 TSDB 引擎儲存結構

TSDB 引擎以 LSM 樹(Log Structured Merge Tree)的結構儲存表資料。例如第 2 節指令碼建立的使用 TSDB 引擎的表 pt1,分割槽 [0, 50) 的資料檔案儲存在 <volumes>/CHUNKS/TSDB_db1/0_50/gE/pt1_2 路徑下,路徑組成同 OLAP 引擎。

在庫名目錄使用 tree 命令檢視內容,可以看到 pt1 表的 level file,也就是 LSM 樹的分層資料檔案,如下所示,其中開頭下劃線前的數字表示層級,目前支援4層:

$ tree
.
├── 0_50
│   └── gE
│       ├── chunk.dict
│       └── pt1_2
│           └── 0_00000623
├── 50_100
│   └── gE
│       ├── chunk.dict
│       └── pt1_2
│           └── 0_00000624
├── dolphindb.lock
├── domain

如果 level file 未及時生成,使用者可以執行 flushTSDBCache(),將 TSDB 引擎緩衝區裡已經完成的事務強制寫入磁碟。

4. 資料更新原理

下面分別介紹 OLAP 和 TSDB 儲存引擎更新分散式表資料的基本原理。

4.1 OLAP 儲存引擎更新原理

更新流程

https://gitee.com/dolphindb/Tutorials_CN/blob/master/images/dolphindb_update/olap_update_flowchart.png

分散式表資料更新過程是一個事務,採用兩階段提交協議和 MVCC 機制,OLAP 引擎資料更新的具體流程如下:

(1)向控制節點申請建立事務,控制節點會給涉及的分割槽加鎖,並分配事務tid,返回分割槽 chunk ID 等資訊;

(2)判斷是否開啟 OLAP cache engine:

  • 如果開啟了 cache engine,先刷寫所有已完成的事務的快取資料到磁碟;
  • 資料寫入 redo log;
  • 在資料節點上建立事務和對應臨時目錄,並更新資料到該目錄下。

通過事務 tid 生成一個臨時的路徑,格式為 ”physicalDir_tid_tidValue”,並把資料更新到該目錄下。如果某些列的資料無變化,則直接建立原列檔案的硬連結;對於 linux 這種支援硬連結但不支援跨 volume,或類似 beegfs 這種不支援硬連結的檔案系統,則採用複製的方式來解決。

如果沒有開啟 cache engine,只做第 2.3 步;

(3)向控制節點申請事務提交的cid。

更新事務 commit 時,生成一個單調遞增的 cid,即 Commit ID 作為提交動作的唯一標識,每個表的元資料有一個 createCids 陣列記錄該 cid;

(4)通知所有事務參與者提交事務:

  • 寫commit redo log並持久化到磁碟;
  • 重新命名臨時目錄為 ”physicalDir_cid“;

(5)通知所有事務參與者完成事務,寫complete redo log。

不管參與者節點是否成功完成事務,協調者都標記完成事務。如果有失敗的情況,通過事務決議和 recovery 機制來恢復。

事務結束後,最終只會保留最後一個版本,因為程式啟動後,其他版本都是歷史資料,應該回收掉,不應該繼續保留。

定期回收機制

在實際操作中,使用者常常會進行多次資料更新,導致上述目錄序列不斷增加。為此,系統提供了定期垃圾回收的機制。預設情況下,系統每隔 60 秒回收一定時間值之前更新生成的目錄。在開始週期性垃圾回收前,系統最多保留 5 個更新版本。

快照隔離級別

更新資料的整個過程是一個事務,滿足 ACID 特性,且通過多版本併發控制機制(MVCC, Multi-Version Concurrency Control)進行讀寫分離,保證了資料在更新時不影響讀取。例如,不同使用者同時對相同資料表進行更新和查詢操作時,系統將根據操作發生的順序為其分配 cid,並將它們和 createCids 數組裡的版本號對比,尋找所有版本號中值最大且小於 cid 的檔案路徑,此路徑即為該 cid 對應的操作路徑。如需要線上獲取最新的 cid,可執行 getTabletsMeta().createCids 命令。

4.2 TSDB 儲存引擎更新原理

建表引數

DolphinDB TSDB 引擎在建表時另外提供了兩個引數:sortColumns 和 keepDuplicates。

  • sortColumns:用於指定表的排序列。系統預設 sortColumns 最後一列為時間列,其餘列欄位作為排序的索引列,其組合值稱作 sortKey。自 2.00.8 版本起,DolphinDB TSDB 引擎開始支援更新 sortColumes 列。
  • keepDuplicates:用於去重,即指定在每個分割槽內如何處理所有 sortColumns 的值相同的資料。引數預設值為 ALL,表示保留所有資料;取值為 LAST 表示僅保留最新資料;取值為 FIRST 表示僅保留第一條資料。

更新策略

不同的 keepDuplicates 引數值,會有不同的資料更新策略。

  1. keepDuplicates=LAST

這種情況下資料更新實質上是向 LSM 樹的記憶體緩衝區追加資料。這部分資料最終會持久化到 level 0 層級的 level file 裡,故不會產生新的版本目錄。通過在 LSM 樹中增加 cid 列來實現 MVCC。查詢時,TSDB 引擎會做過濾,只返回最新的資料。

寫入量達到一定值或更新後一段時間內,會自動合併 level file 以節省硬碟空間。若未及時觸發 level file 的合併,可以手動執行 triggerTSDBCompaction() 強制觸發指定 chunk 內 level 0 級別的所有 level file 的合併操作。

更新流程圖如下:

(1)向控制節點申請建立事務,控制節點會給涉及的分割槽加鎖,並分配事務tid,返回分割槽 chunk ID 等資訊;

(2)TSDB 必須開啟 cache engine:

  • 刷寫 cache engine 裡所有已完成的事務的快取資料到磁碟;
  • 資料寫入 redo log;
  • 讀取需要更新的資料到記憶體並更新,即只讀取需要更新的 level file 的部分資料;

(3)向控制節點申請事務提交的cid。

更新事務 commit 時,生成一個單調遞增的 cid,即 Commit ID 作為提交動作的唯一標識,每個表的元資料有一個 createCids 陣列記錄該 cid;

(4)通知所有事務參與者提交事務,寫commit redo log並持久化到磁碟;

(5)通知所有事務參與者完成事務:

  • 寫 complete redo log;
  • 寫入更新的資料到 cache engine,cache engine 的後臺執行緒會非同步寫入資料到磁碟。

2. keepDuplicates=FIRST 或 keepDuplicates=ALL

在這兩種情況下,更新操作流程與 OLAP 基本相同,也是採用兩階段提交協議,每個分割槽每次更新產生一個獨立的目錄,且整個更新過程是一個事務,具備 ACID 特性,通過 MVCC 實現快照隔離級別。過期版本的清理機制也與 OLAP 相同。

但是第 2.3 步讀取要更新的資料到記憶體並更新到臨時目錄,TSDB keepDuplicates=FIRST 或 ALL 策略與 OLAP 不同,會讀出所有檔案進行更新,即未變化的列也會被更新,然後將更新的 level file 資訊寫入到元資料中。因此,我們也建議使用者首先確定分割槽資料量較小(不能大於可用記憶體空間)再進行更新操作,否則容易導致記憶體溢位。

5. 資料更新實驗

接下來我們通過實驗來驗證資料更新的基本原理,並對比分析 OLAP 和 TSDB 引擎在常見場景的效能特點。

5.1 實驗準備

部署叢集

  • Linux 系統
  • DolphinDB v2.00.7 版本
  • 單機叢集部署1個控制節點+1個數據節點
  • 單 SSD 硬碟,硬碟速度為 6 Gbps,檔案系統為 xfs
  • 開啟 cache engine 和 redo log

建立庫表和寫入資料

參考《DolphinDB入門:物聯網範例》第2.3、2.4節,建立多值模型資料庫表,並寫入資料。注意此處指令碼為非同步寫入,可以通過 getRecentJobs() 方法檢視寫入是否完成。

本實驗將模擬 100 臺機器 5 天的資料量,每臺機器每天產生 86400 條記錄,5 天總資料量為 43200000 條。OLAP 和 TSDB 引擎的基本資料和建庫名如下表所示:

OLAP TSDB
佔用磁碟空間 8.3 GB 8.3 G
每個分割槽大小 169 MB 170 MB
建庫名 olapDemo tsdbDemo

參考以下指令碼修改《DolphinDB入門:物聯網範例》2.3 節的 createDatabase 函式。注意實驗中需要修改 createPartitionedTable 函式的 keepDuplicates 引數值:

def createDatabase(dbName,tableName, ps1, ps2, numMetrics){
	m = "tag" + string(1..numMetrics)
	schema = table(1:0,`id`datetime join m, [INT,DATETIME] join take(FLOAT,numMetrics) )
	db1 = database("",VALUE,ps1)
	db2 = database("",RANGE,ps2)
	db = database(dbName,COMPO,[db1,db2],,'TSDB')
	db.createPartitionedTable(schema,tableName,`datetime`id ,,`id`datetime, keepDuplicates=LAST)
}

實驗的基本思路為觀察執行 update 語句前後資料目錄和檔案的變化與上文闡述的原理是否一致。

5.2 OLAP 引擎更新實驗

  • 更新前

首先進入到需要更新的資料所在目錄,預設位置在 //storage/CHUNKS/olapDemo/20200901/1_11/2。其中,最後的 2 為表的物理名索引。通過 tree 命令檢視 machines 表的列資料檔案:

$ tree
.
└── 2
    └── machines_2
        ├── datetime.col
        ├── id.col
        ├── tag10.col
        ├── tag11.col
         ...
        └── tag9.col
  • 執行更新

在 GUI 執行如下指令碼,對分割槽 20200901 下分割槽 1_11 裡的資料進行 20 次更新:

machines = loadTable("dfs://olapDemo", "machines")
for(i in 0..20)
	update machines set tag1=i,tag5=i where id in 1..5,date(datetime)=2020.09.01

更新過程中使用 ll 命令可以看到,命名帶 tid 的中間資料夾已生成:

$ ll
total 20
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_115
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_116
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_117
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_118
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_119
drwxrwxr-x 2 dolphindb dolphindb  120 Sep  7 05:26 machines_2_tid_120
  • 更新後

檢視目錄檔案,如果沒觸發週期性清理舊版本,可以看到只保留了5個更新版本:

$ ll
total 20
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_121
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_122
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_123
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_124
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_125

在觸發週期性清理舊版本前,使用 ll 命令檢視更新後的列資料檔案,注意到只有更新的列 tag1 和 tag5 的資料檔案連結數為 1,其他資料檔案連結數均為 5 即硬連結。這是因為只更新了 tag1 和 tag5 的列,其他列無變化,因此直接建立了硬連結。如下所示:

$ ll machines_2_125/
total 169632
-rw-rw-r-- 5 dolphindb dolphindb 3469846 Sep  7 05:15 datetime.col
-rw-rw-r-- 5 dolphindb dolphindb   14526 Sep  7 05:15 id.col
-rw-rw-r-- 5 dolphindb dolphindb 3469845 Sep  7 05:15 tag10.col
-rw-rw-r-- 5 dolphindb dolphindb 3469846 Sep  7 05:15 tag11.col
...
-rw-rw-r-- 1 dolphindb dolphindb 1742158 Sep  7 05:26 tag1.col
...
-rw-rw-r-- 1 dolphindb dolphindb 1742158 Sep  7 05:26 tag5.col
...

更新後過一段時間,發現只保留了最新的版本。這是因為系統會定時進行回收,最終只保留一個最新的副本。如下所示:

$ ll
total 4
drwxrwxr-x 2 dolphindb dolphindb 4096 Sep  7 05:26 machines_2_125

5.3 TSDB 引擎更新實驗

keepDuplicates = LAST

  • 更新前

首先設定 createPartitionedTable 方法的 keepDuplicates 引數為 LAST,然後建庫和匯入資料。

進入需要更新的資料所在的目錄,預設位置在 //storage/CHUNKS/tsdbDemo/20200901/1_11/S,最後的 S 為表的物理名索引。用 tree 命令檢視 machines 表的 level file:

$ tree
.
├── chunk.dict
└── machines_2
    ├── 0_00000010
    ├── 0_00000011
    ├── 0_00000012
    ├── 0_00000013
    ├── 0_00000014
    └── 1_00000002

1 directory, 7 files
  • 執行更新

在 GUI 執行如下指令碼,對分割槽 20200901 下分割槽 1_11 裡的資料進行 20 次更新:

machines = loadTable("dfs://tsdbDemo", "machines")
for(i in 0..20)
	update machines set tag1=i,tag5=i where id in 1..5,date(datetime)=2020.09.01

更新時或更新後,用 tree 命令檢視資料檔案,可見並沒有生成新版本的臨時目錄,但 machines_2 目錄下的 level file 變多,說明 keepDuplicates =LAST 時,更新等同於追加資料。如下所示:

$ tree
.
├── chunk.dict
└── machines_2
    ├── 0_00000010
    ├── 0_00000011
    ├── 0_00000012
    ├── 0_00000013
    ├── 0_00000014
    ├── 0_00000241
    ├── 0_00000243
     ...
    ├── 1_00000002
    ├── 1_00000050
    └── 1_00000051

1 directory, 21 files
  • 更新後

更新後過一段時間,用 tree 命令檢視資料檔案,發現 level file 進行了合併。合併 level file 時,系統會自動刪除更新時的冗餘資料,數量由 20 個減少為 6 個。如下所示:

tree
.
├── chunk.dict
└── machines_2
    ├── 0_00000272
    ├── 0_00000274
    ├── 0_00000276
    ├── 1_00000002
    ├── 1_00000050
    └── 1_00000051

1 directory, 7 files

keepDuplicates = ALL

  • 更新前

設定 createPartitionedTable 方法的 keepDuplicates 引數為 ALL,然後建庫和匯入資料。

通過 tree 命令檢視 machines 表的 level file:

$ tree
.
├── chunk.dict
└── machines_2
    ├── 0_00000273
    ├── 0_00000275
    ├── 0_00000277
    ├── 0_00000278
    ├── 0_00000279
    └── 1_00000054

1 directory, 7 files
  • 執行更新

更新過程中使用 tree 命令可以看到,有命名包含 tid 的中間資料夾生成:

$ tree
.
├── chunk.dict
├── machines_2
│   ├── 0_00000273
│   ├── 0_00000275
│   ├── 0_00000277
│   ├── 0_00000278
│   ├── 0_00000279
│   └── 1_00000054
└── machines_2_tid_199
    ├── 0_00000515
    ├── 0_00000516
    ├── 0_00000517
    ├── 0_00000518
    └── 0_00000519
  • 更新後

使用 tree 命令,可以看到如果沒觸發週期性清理舊版本,則保留了 5 個更新版本,如下所示:

$ tree
.
├── chunk.dict
├── machines_2_215
│   ├── 0_00000595
│   ├── 0_00000596
│   ├── 0_00000597
│   ├── 0_00000598
│   └── 0_00000599
├── machines_2_216
│   ├── 0_00000600
│   ├── 0_00000601
│   ├── 0_00000602
│   ├── 0_00000603
│   └── 0_00000604
├── machines_2_217
│   ├── 0_00000605
│   ├── 0_00000606
│   ├── 0_00000607
│   ├── 0_00000608
│   └── 0_00000609
├── machines_2_218
│   ├── 0_00000610
│   ├── 0_00000611
│   ├── 0_00000612
│   ├── 0_00000613
│   └── 0_00000614
└── machines_2_219
    ├── 0_00000615
    ├── 0_00000616
    ├── 0_00000617
    ├── 0_00000618
    └── 0_00000619

在觸發週期性清理舊版本前,使用 ll 檢視更新後的列資料檔案,注意到所有 level file 連結數均為1,即不存在硬連結:

$ ll machines_2_219
total 284764
-rw-rw-r-- 1 dolphindb dolphindb 57151251 Sep  7 05:48 0_00000615
-rw-rw-r-- 1 dolphindb dolphindb 57151818 Sep  7 05:48 0_00000616
-rw-rw-r-- 1 dolphindb dolphindb 58317419 Sep  7 05:48 0_00000617
-rw-rw-r-- 1 dolphindb dolphindb 59486006 Sep  7 05:48 0_00000618
-rw-rw-r-- 1 dolphindb dolphindb 59482644 Sep  7 05:48 0_00000619

更新後過一段時間,發現只保留了最新的版本:

$ tree 
.
├── chunk.dict
└── machines_2_219
    ├── 0_00000615
    ├── 0_00000616
    ├── 0_00000617
    ├── 0_00000618
    └── 0_00000619

1 directory, 6 files

keepDuplicates = FIRST

createPartitionedTable 方法的 keepDuplicates 引數為 FIRST 時更新操作的表現與 keepDuplicates 引數為 ALL 時相同。

6. 效能分析

在上文實驗的基礎上,我們重複執行迴圈更新指令碼,並統計耗時。

更新 1 條記錄的 2 列指令碼如下:

machines = loadTable("dfs://olapDemo", "machines")
timer update machines set tag1=1, tag5=5 where id=1 and datetime=2020.09.01T00:00:00

更新 20 次 分割槽 20200901 下分割槽 1_11 裡的資料,總計432000*20=8640000條記錄,2 列指令碼如下:

machines = loadTable("dfs://olapDemo", "machines")
timer{
for(i in 0..20)
	update machines set tag1=i,tag5=i where id in 1..5,date(datetime)=2020.09.01
}

更新 20 次 分割槽 20200901 下分割槽 1_11 裡的資料,總計432000*20=8640000條記錄,20 列指令碼如下:

machines = loadTable("dfs://olapDemo", "machines")
timer{
for(i in 0..20)
	update machines set tag1=i,tag2=i,tag3=i,tag4=i,tag5=i,tag6=i,tag7=i,tag8=i,tag9=i,tag10=i,tag11=i,tag12=i,tag13=i,tag14=i,tag15=i,tag16=i,tag17=i,tag18=i,tag19=i,tag20=i where id in 1..5,date(datetime)=2020.09.01
}

統計更新操作耗時如下表:

配置 第一次執行耗時(ms) 第二次執行耗時(ms) 第三次執行耗時(ms)
OLAP
更新1條記錄的2列 131.263 135.649 150.013
更新8640000條記錄的2列 1,389.31 1,414.918 1,331.718
更新8640000條記錄的20列 6,309.484 5,800.256 5,511.421
TSDB,keepDuplicates=LAST
更新1條記錄的2列 29.745 31.686 29.333
插入1條記錄 10.002 12.259 10.14
更新8640000條記錄的2列 19,358.699 21,832.69 19,686.798
更新8640000條記錄的20列 20,782.819 22,750.596 20,643.41
插入8640000條記錄 10,813.92 9,506.557 12,695.168
TSDB,keepDuplicates=ALL
更新8640000條記錄的20列 69,385.771 70,563.928 62,621.552
TSDB,keepDuplicates=FIRST
更新8640000條記錄的20列 57,614.807 65,081.804 58,425.8
注:程式執行效能受硬體效能、系統執行狀況等因素影響,該表格執行耗時僅供參考。
  • 儲存引擎配置為 OLAP 時

更新效能與需要更新的列數有關,因為更新操作實現為重新生成需要更新的列,而對未更新的列使用了硬連結。故更新20列比更新2列耗時明顯長。

  • 儲存引擎配置為 TSDB keepDuplicates=LAST 時

效能相較 keepDuplicates=ALL 或 keepDuplicates=FIRST 更好,因為更新操作只需要向 LSM 樹的追加資料,而 LSM 樹具有吞吐量大的特點,寫效能優異。更新效能比插入效能慢2-3倍,是因為更新需要先讀取資料到記憶體,而插入不需要。

  • 儲存引擎配置為 TSDB keepDuplicates=ALL 或 FIRST 時

更新效能較差,因為該配置下每次更新都會在一個新的目錄產生一個新的版本,且未變化的列也會被更新,磁碟IO較大,故而效能較差。

綜上所述,DolphinDB 只適合低頻更新。使用 TSDB 引擎時,若對更新的效能有要求,建議配置 keepDuplicates=LAST。

7. 總結

本文對比介紹了 OLAP 和 TSDB 兩種儲存引擎更新分散式表資料的使用方法和基本原理,通過實驗來驗證基本原理,並分析了常見場景的效能問題。

OLAP 儲存引擎的更新效能與需要更新的列數和作業系統是否支援硬連結有關。TSDB 儲存引擎的更新效能與建表引數 keepDuplicates 有關,建表引數 keepDuplicates=LAST 比 TSDB keepDuplicates=ALL 或 FIRST 時更新效能更好。

實際應用中使用哪種引擎需要考慮更多的應用場景和實際的效能,更多詳細資訊可見 DolphinDB 資料模型