MaxCompute在Append Delta Table表格式中進一步支援Hash Cluster,在支援增量資料處理的同時提升查詢效能。本文介紹其與其他表類型的差異、建表文法、SQL及資料通道 SDK 使用樣本。
適用情境
推薦在以下情境使用 Hash Cluster:
等值過濾查詢:按固定列做點查或等值過濾,減少掃描量。
等值JOIN / GROUP BY:多表按相同KEY關聯或彙總,減少 Shuffle。
與相似表類型對比
表類型 | 聚簇方式 | 增量寫入(ACID) | |
Hash | 不支援 | 有 Hash Clustering(Shuffle + Sort)最佳化,但不支援 ACID。 | |
Hash | 支援 | 有 ACID 能力與 Hash Clustering 最佳化,適用於有主鍵資料。讀寫效能弱於無主鍵的表。 | |
Range | 支援 | 有 ACID 能力與重聚簇支援,但聚簇方式為 Range,寫入效能弱於 Hash。 | |
Append Delta Table - Hash Cluster | Hash | 支援 | 集 Hash Clustering 最佳化(Shuffle + Sort)與完整 ACID 能力於一體,同時支援後台增量與全量重聚簇。是上述三類表中綜合能力最完整的類型。 |
前提條件
開啟以下 Session 參數後再建表:
SET odps.table.append2.enable=true;
SET odps.table.hash.delta.enable=true; -- hash delta 建表試用開關建表文法
CREATE TABLE [IF NOT EXISTS] <table_name>
[(<col_name> <data_type> [comment <col_comment>], ...)]
[PARTITIONED BY (<col_name> <data_type> [comment <col_comment>], ...)]
CLUSTERED BY (<col_name> [, <col_name>, ...])
[SORTED BY (<col_name> [, <col_name>, ...])] -- 僅支援升序
INTO <number_of_buckets> BUCKETS
TBLPROPERTIES ('table.format.version' = '2'); 參數說明:
參數 | 說明 |
| 指定 Hash 分桶列。建議選擇在等值過濾、JOIN、GROUP BY 或 WINDOW PARTITION BY 中頻繁使用的列,且該列的取值種類盡量多,以充分發揮分桶效果。 |
| 可選。指定桶內排序列。當前僅支援升序排序。建議選擇範圍/等值過濾列、視窗計算或版本時間列。 |
| 指定邏輯 Bucket 數。建議結合資料量、查詢並發和分桶列基數設定。 Bucket 數量和寫表時並發度,讀表 Shuffle 最佳化時並發度相關。 |
| 設定為 |
SQL 使用樣本
本樣本以商品狀態和價格版本表為例。業務上通常會按 item_id 點查或關聯商品,因此將 item_id 作為 Hash 分桶列;版本生效時間 event_time 用於查看歷史變化,因此將 event_time 作為桶內排序列。該設計適用於緩慢變化維表、商品價格版本表、狀態變更明細表等情境。
準備工作
SET odps.sql.type.system.odps2=true;
SET odps.table.append2.enable=true;
SET odps.table.hash.delta.enable=true;建表
非分區表
CREATE TABLE hash_delta_sales_demo (
item_id BIGINT,
event_time TIMESTAMP,
price DOUBLE,
status STRING
)
CLUSTERED BY (item_id)
SORTED BY (event_time)
INTO 256 BUCKETS
TBLPROPERTIES ('table.format.version' = '2');分區表
如果資料需要按日期管理,也可以建立分區表:
CREATE TABLE hash_delta_sales_demo_pt (
item_id BIGINT,
event_time TIMESTAMP,
price DOUBLE,
status STRING
)
PARTITIONED BY (ds STRING)
CLUSTERED BY (item_id)
SORTED BY (event_time)
INTO 256 BUCKETS
TBLPROPERTIES ('table.format.version' = '2');通過DESC EXTENDED hash_delta_sales_demo;查看錶資訊。表的分桶和排序定義如下:
ClusterType: hash
BucketNum: 256
ClusterColumns: [item_id]
SortColumns: [event_time ASC]增量寫入
以下以非分區表為例,示範增量寫入和重聚簇過程。
初始寫入資料:
INSERT INTO TABLE hash_delta_sales_demo VALUES (1001, TIMESTAMP '2026-05-01 10:00:00', 10.00, 'active'), (1001, TIMESTAMP '2026-05-03 10:00:00', 13.00, 'active'), (1002, TIMESTAMP '2026-05-01 11:00:00', 20.00, 'active'); DESC EXTENDED hash_delta_sales_demo;刪除操作
刪除一部分資料後查看錶狀態:
DELETE FROM hash_delta_sales_demo WHERE item_id = 1002; DESC EXTENDED hash_delta_sales_demo;補寫歷史資料
補寫一條歷史版本。該版本的 event_time 位於 item_id=1001 已有時間範圍中間:
INSERT INTO TABLE hash_delta_sales_demo VALUES (1001, TIMESTAMP '2026-05-02 09:00:00', 12.00, 'active'); DESC EXTENDED hash_delta_sales_demo;
Bucket Pruning
對分桶列做等值查詢時,MaxCompute 會根據 Hash 分布直接定位目標 Bucket,跳過其餘 Bucket 的掃描。以下查詢按 item_id = 1001 過濾,實際唯讀取該值所在的 1 個邏輯Bucket,而非全表掃描:
SELECT * FROM hash_delta_sales_demo
WHERE item_id = 1001
ORDER BY event_time
LIMIT 10;
-- 返回結果:
+------------+---------------------+------------+--------+
| item_id | event_time | price | status |
+------------+---------------------+------------+--------+
| 1001 | 2026-05-01 10:00:00 | 10.0 | active |
| 1001 | 2026-05-02 09:00:00 | 12.0 | active |
| 1001 | 2026-05-03 10:00:00 | 13.0 | active |
+------------+---------------------+------------+--------+全量重聚簇
如果需要重新整理存量資料,執行 RECLUSTER FULL。該操作會保留表中的歷史資料語義,並按照當前表定義重新組織儲存資料。
ALTER TABLE hash_delta_sales_demo RECLUSTER FULL;
DESC EXTENDED hash_delta_sales_demo;Hash Delta 表支援 INSERT、UPDATE、DELETE、MERGE INTO 等增量寫入,同時保留 Hash 分布資訊。最佳化器基於當前資料狀態選擇執行計畫:資料有序時利用有序儲存,資料變為非全量有序後仍可利用 Hash 分桶,必要時通過RECLUSTER FULL 恢複全量排序。
資料通道使用樣本
以上文中 hash_delta_sales_demo 表為例,介紹通過Data Transmission Service SDK 進行 Hash Clustered Delta Table 的資料上傳/下載。
匯入SDK依賴包
建議使用最新版本,至少需要升級到0.59版本及以上。詳情參見版本更新記錄。
範例程式碼
常見問題
如何選擇合適的單 Bucket 儲存量?
建議將單 Bucket 儲存量控制在數百 MB 到數十 GB 之間。
Bucket 過小:儲存開銷上升,Shuffle 代價增大。
Bucket 過大:寫表時間較長,查詢時 Bucket Pruning 的過濾效果下降, Shuffle 最佳化效果下降。
建議根據預期資料增長量(而非當前量)來設定 Bucket 數,避免頻繁修改表結構。
如果業務資料量確實偏大,單 Bucket 也可支援更大儲存,也可以將 Bucket Num 設定的更大,但需結合實際寫入與查詢效能綜合評估。