目錄
簡要流程
詳細流程
1. UPDATE 語句執行流程
2. 如何更新表的數據
3. 是否支持事務
總結關鍵點
簡要流程
- 前端處理(FE):
-
- 解析 SQL 并驗證主鍵條件
- 生成包含主鍵列表和新值的更新計劃
- 按主鍵哈希分發到對應 BE
- 后端執行(BE核心流程):
-
- 通過主鍵索引快速定位數據位置
- 采用"讀-改-寫"模式(非就地更新)
- 對同一主鍵的多版本數據保留最新值
- 提交與清理:
-
- 元數據原子切換確保查詢一致性
- 異步 Compaction 回收舊數據空間
- 寫時復制(Copy-on-Write)機制保證讀穩定性
詳細流程
StarRocks 的 UPDATE
語句是其 異步主鍵更新模型 的核心功能(自 2.3 版本引入,并持續優化),專為高效處理按主鍵進行批量更新的場景設計。其實現與傳統的 OLTP 數據庫有顯著區別,充分利用了列式存儲和 MPP 架構的優勢。下面詳細介紹你關心的三個方面:
1. UPDATE 語句執行流程
StarRocks 的 UPDATE
操作是一個異步、批處理的過程,主要發生在后臺的 BE(Backend)節點上,大致流程如下:
- 用戶提交 UPDATE 語句:
-
- 用戶通過 MySQL 客戶端或其他兼容工具向 FE(Frontend)提交標準的 SQL
UPDATE
語句。 - 示例:
UPDATE table_name SET column1 = value1 [, column2 = value2 ...] WHERE pk_column = some_value [AND ...];
- 用戶通過 MySQL 客戶端或其他兼容工具向 FE(Frontend)提交標準的 SQL
- FE 解析與計劃生成:
-
- FE 解析 SQL,驗證語法、權限、目標表和列是否存在、WHERE 條件是否包含完整主鍵(或其等價條件)。
- FE 生成一個邏輯更新計劃。這個計劃主要包含兩部分信息:
-
-
- 需要更新的行定位信息: 基于 WHERE 條件(必須能精確定位到主鍵)計算出哪些主鍵值對應的行需要被修改。
- 新的列值: 指定的 SET 子句中的新值。
-
- 數據分發到 BE:
-
- FE 將邏輯更新計劃(主要是主鍵列表和對應的新值集合)分發給存儲了相關數據分片的 BE 節點。
- 分發策略基于主鍵的哈希值,確保包含特定主鍵行的 Tablet(數據分片)所在的 BE 收到該行的更新請求。
- BE 執行更新操作(核心 - 讀改寫):
-
- 每個 BE 收到屬于自己 Tablet 的更新任務后,執行以下關鍵步驟:
-
-
- a. 定位數據文件: 利用主鍵索引快速定位包含目標主鍵行的數據文件(Segment 文件)。主鍵索引是存儲在內存中的。
- b. 讀取原始行: 讀取包含目標行的整個 Segment 文件(或相關的行組)。
- c. 應用更新: 在內存中,根據 UPDATE 語句的 SET 子句,修改讀取到的目標行的對應列值。
- d. 排序與去重: 對這批更新后的行(可能包含同一主鍵的多次更新)按主鍵排序,并只保留最新版本(基于操作序列號或時間戳)。這是保證主鍵唯一性和最終一致性的關鍵。
- e. 寫入新文件: 將排序去重后的這批更新行(連同該 Segment 中未修改的行)寫入一個新的 Segment 文件。原始文件不會被就地修改。
- f. 提交元數據: 向 FE 報告新生成的 Segment 文件信息,并更新元數據(如版本號)。
-
- 垃圾回收(Compaction):
-
- 新 Segment 文件寫入成功后,舊的 Segment 文件(包含被更新行原始數據)會被標記為可刪除。
- 后臺的 Compaction 進程(Base Compaction 或 Cumulative Compaction)會異步地將包含多個版本數據的 Segment 文件合并壓縮,物理刪除被覆蓋的舊數據行,回收存儲空間。
2. 如何更新表的數據
- 基于主鍵: UPDATE 必須指定完整的主鍵或能等價推導出主鍵的 WHERE 條件(例如
WHERE primary_key_col = ?
)。這是 StarRocks 高效定位數據的基礎。 - 列式更新: 在 SET 子句中指定需要更新的列及其新值。未指定的列保持不變。
- “讀-改-寫”模式: 核心機制是讀取包含目標行的原始數據塊 -> 在內存中修改目標列 -> 將修改后的整行(連同該塊中未修改的行)寫入新文件。不是直接在原存儲位置修改位圖或單個值。
- 批量處理: 一次 UPDATE 操作通常涉及一批行的更新(即使 SQL 看起來只更新一行,內部也可能批量處理)。BE 在內存中處理一批更新,排序去重后一次性寫入新文件,效率遠高于單行更新。
- 寫時復制 (Copy-on-Write): 更新操作通過創建包含新數據的新文件(Segment)來實現,原始文件保持不變直到被異步回收。這保證了高并發讀操作的穩定性(讀操作總是訪問舊的、一致的文件版本,直到新版本提交)。
- 原子性與版本化: 新 Segment 文件的寫入和元數據的更新(版本切換)是原子的。查詢在某個時間點看到的總是某個一致的數據版本。
3. 是否支持事務
StarRocks 的 UPDATE
語句在單個語句級別提供原子性和持久性:
- 原子性 (Atomicity per Statement):
-
- 單行更新: 對一個主鍵行的所有列更新是原子的。要么所有指定列都更新成功,要么都不更新。
- 多行更新: 同一批處理內更新的多行操作也具有原子性。這意味著在 BE 處理一批更新時,這批中的所有行更新要么全部成功寫入新 Segment 并提交(元數據更新),要么全部失敗(例如 BE 崩潰)。用戶不會看到部分更新的狀態。
- 隔離性 (Isolation):
-
- StarRocks 使用 MVCC (多版本并發控制)。UPDATE 操作創建數據的新版本。
- 正在進行的 UPDATE 操作不會阻塞讀操作。讀操作(如 SELECT)會讀取操作開始時已提交的最新版本數據(快照隔離),看不到正在進行的 UPDATE 產生的中間狀態或未提交的新版本。
- 多個并發的 UPDATE 操作修改同一主鍵行時,基于操作序列號或時間戳,只有最后一個成功的 UPDATE 會生效(最終一致性)。在 BE 處理階段,排序去重步驟保證了這一點。用戶可能會看到基于主鍵的“最后寫入獲勝”行為。
- 持久性 (Durability): 一旦 UPDATE 操作成功提交(元數據更新完成),數據就持久化寫入磁盤。即使發生節點故障,已提交的數據也不會丟失。
- 多語句事務:
-
- 社區版: 不支持 跨多個 SQL 語句(如
BEGIN; UPDATE ...; UPDATE ...; COMMIT;
)的 ACID 事務。每個UPDATE
語句是獨立提交的。 - 企業版: 支持 有限的多語句事務 (自 3.0 版本引入)。在一個顯式的
BEGIN
/COMMIT
/ROLLBACK
塊內執行的多個 DML 語句(INSERT, UPDATE, DELETE)可以作為一個原子操作提交或回滾。這是通過 FE 協調和內存隊列實現的,但有容量和超時限制,主要用于小批量、短時操作。它不是傳統 OLTP 數據庫那種支持長時間運行、大事務的強事務模型。
- 社區版: 不支持 跨多個 SQL 語句(如
總結關鍵點
- 流程: 解析 -> 定位主鍵 -> 分發 -> (BE)讀原始數據 -> 改內存數據 -> 排序去重 -> 寫新文件 -> 提交元數據 -> 異步回收舊文件。
- 更新機制: 基于主鍵,批量處理,讀-改-寫模式,寫時復制(創建新文件),利用主鍵索引和排序去重保證效率與主鍵唯一性。
- 事務: 單條 UPDATE 語句具有原子性和持久性,通過 MVCC 提供快照隔離級別的讀一致性。社區版不支持多語句事務,企業版提供有限的多語句事務支持。
理解 StarRocks 的 UPDATE 是面向分析場景優化的、基于主鍵的異步批量更新機制,而非 OLTP 式的逐行實時更新,對于正確使用和性能調優至關重要。它非常適合數據修正、緩慢變化維度(SCD Type 1/2)、標簽更新等場景。