ClickHouse 能夠支撐高性能資料查詢的核心秘密之一,就是其強大的儲存引擎 — MergeTree。這一篇將帶你深入理解 MergeTree 是什麼、它解決了哪些問題,以及如何透過不同的變種引擎 (ReplacingMergeTree, SummingMergeTree 等) 應對不同資料處理場景。
MergeTree 是 ClickHouse 中最基礎的儲存引擎,負責將大量寫入資料有效儲存與管理,並支援高效的查詢與資料合併(Merge)操作。
- Sorting:資料根據 Sorting Key(如 town, street)進行排序,並產生一個稀疏主鍵索引(Sparse Primary Index)。
- Splitting:排序後的資料會被拆分成單獨的欄位。
- Compression:每個欄位分別進行壓縮處理,應用 LZ4、ZSTD 等壓縮算法。
後續透過背景合併 (Merge) 將小片段整理成大型優化片段。
MergeTree 家族的引擎具備以下幾個特性:
Primary Key 排序與稀疏索引 (Sparse Primary Index):表格的主鍵決定了每個資料片段 (Data Part) 內的排序方式(Clustered Index)。不過,這個索引並不指向單筆資料,而是以 8192 筆資料為單位的 Granule (粒度)。這種設計讓主鍵索引即便在超大資料量下仍能被保留在記憶體中,並且能有效快速地存取磁碟上的資料區塊。
靈活的分區機制 (Partitioning):使用任意表達式來劃分分區,並能透過 Partition Pruning 技術在查詢時自動跳過不相關的分區,避免不必要的 I/O。
高可用性與容錯 (Replication):資料可於多個 Cluster Nodes 間進行複製,支援高可用性、故障切換 (Failover)、以及無停機升級 (Zero Downtime Upgrade)。
統計與抽樣查詢 (Sampling & Statistics):MergeTree 支援各類型的統計與抽樣機制,可協助查詢優化器進行查詢路徑選擇與加速。
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr1] [COMMENT ...] [CODEC(codec1)] [STATISTICS(stat1)] [TTL expr1] [PRIMARY KEY] [SETTINGS (name = value, ...)],
name2 [type2] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr2] [COMMENT ...] [CODEC(codec2)] [STATISTICS(stat2)] [TTL expr2] [PRIMARY KEY] [SETTINGS (name = value, ...)],
...
INDEX index_name1 expr1 TYPE type1(...) [GRANULARITY value1],
INDEX index_name2 expr2 TYPE type2(...) [GRANULARITY value2],
...
PROJECTION projection_name_1 (SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY]),
PROJECTION projection_name_2 (SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr
[DELETE|TO DISK 'xxx'|TO VOLUME 'xxx' [, ...] ]
[WHERE conditions]
[GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ] ]
[SETTINGS name = value, ...]
CREATE TABLE user_events
(
EventDate Date,
UserID UInt64,
EventType String,
EventValue Float32
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(EventDate)
ORDER BY (EventDate, UserID);
INSERT INTO user_events VALUES ('2025-08-10', 1001, 'click', 1.0);
INSERT INTO user_events VALUES ('2025-08-10', 1002, 'view', 1.0);
INSERT INTO user_events VALUES ('2025-08-11', 1001, 'purchase', 299.99);
SELECT *
FROM user_events
WHERE EventDate = '2025-08-10'
AND UserID = 1001;
此查詢會根據 Partition 先裁剪至 2025-08 分區,再透過 Primary Key (EventDate, UserID) 直接命中相關 Granule,大幅減少掃描資料量。
若想更細緻控制 Primary Index 的粒度大小,可以透過 index_granularity
參數:
ENGINE = MergeTree()
PARTITION BY toYYYYMM(EventDate)
ORDER BY (EventDate, UserID)
SETTINGS index_granularity = 8192;
8192 是預設 Granule 大小,若資料查詢行為較分散,也可以調整為更小的粒度 (如 4096) 來提升查詢命中率,但會增加索引體積。
Granularity 會在後面的篇幅中詳細描述,由於這是額外補充,日後了解 Granularity 的定義和用途,可以再回來看補充~
ClickHouse 根據不同業務需求,衍生出許多 MergeTree 變種引擎:
儲存引擎 | 特性與應用場景 |
---|---|
ReplacingMergeTree | 自動以指定欄位 (如 version 欄位) 替換重複資料,適合資料需去重的場景。 |
SummingMergeTree | 在合併時自動將相同 Primary Key 的數值欄位進行加總,適用於資料匯總場景。 |
AggregatingMergeTree | 針對 AggregateFunction 資料型別做更複雜的聚合運算,適合實時指標統計場景。 |
CollapsingMergeTree | 透過 sign 欄位標記資料新增/刪除狀態,自動實現邏輯刪除與衝突解決。 |
VersionedCollapsingMergeTree | 在 Collapsing 基礎上支援版本控制的資料去重。 |
各位放心,我們這次的鐵人賽都會講到 😎🚀 (做死),每個 MergeTree 變種都有各自不同的長處及應用場景,根據需求謹慎購買。
MergeTree 會在背景執行 Merge 操作,將多個小型 Data Part 合併成大型 Part,並在此過程中進行排序、壓縮與去重。
max_parts_to_merge_at_once
)可平衡查詢與寫入效能。ReplacingMergeTree
去重資料、SummingMergeTree
快速整理使用者點擊行為。AggregatingMergeTree
實時統計各種資料指標。MergeTree 是 ClickHouse 高效能儲存與查詢的基礎,透過分區、排序與背景 Merge 機制,使得海量資料寫入與查詢皆能達到極致效能。針對不同業務場景選擇合適的 MergeTree 變種引擎,能夠很大的提升系統性能。