ClickHouse(11)ClickHouse合併樹MergeTree家族表引擎之SummingMergeTree詳細解析

張飛的豬發表於2023-01-16

SummingMergeTree引擎繼承自MergeTree。區別在於,當合並SummingMergeTree表的資料片段時,ClickHouse會把所有具有相同主鍵的行合併為一行,該行包含了被合併的行中具有數值資料型別的列的彙總值。如果主鍵的組合方式使得單個鍵值對應於大量的行,則可以顯著的減少儲存空間並加快資料查詢的速度。

一般SummingMergeTree和MergeTree一起使用。例如,在準備做報告的時候,將完整的資料儲存在MergeTree表中,並且使用SummingMergeTree來儲存聚合資料。這種方法可以避免因為使用不正確的主鍵組合方式而丟失有價值的資料。

建表語法

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = SummingMergeTree([columns])
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

建立SummingMergeTree表的引數中,與MergeTree不同的是[columns]。columns包含了將要被彙總的列的列名的元組。屬於可選引數。所選的列必須是數值型別,並且不可位於主鍵中。

如果沒有指定columns,ClickHouse會把所有不在主鍵中的數值型別的列都進行彙總。

其他的引數與MergeTree表是一致。

MergeTree表引擎的解析可以參考ClickHouse(09)ClickHouse合併樹MergeTree家族表引擎之MergeTree詳細解析

-- 建表
CREATE TABLE summtt
(
    key UInt32,
    value UInt32
)
ENGINE = SummingMergeTree()
ORDER BY key;

-- 插入資料
INSERT INTO summtt Values(1,1),(1,2),(2,1);

-- 查詢資料
-- ClickHouse可能不會完整的彙總所有行,因此在查詢中使用了聚合函式sum和GROUP BY子句。
-- ClickHouse定期合併插入的資料片段,並在這個時候對所有具有相同主鍵的行中的列進行彙總,將這些行替換為包含彙總資料的一行記錄。
SELECT key, sum(value) FROM summtt GROUP BY key;

-- 查詢結果
┌─key─┬─sum(value)─┐
│   2 │          1 │
│   1 │          3 │
└─────┴────────────┘

資料處理

當資料被插入到表中時,他們將被原樣儲存。ClickHouse定期合併插入的資料片段,並在這個時候對所有具有相同主鍵的行中的列進行彙總,將這些行替換為包含彙總資料的一行記錄。

ClickHouse會按片段合併資料,以至於不同的資料片段中會包含具有相同主鍵的行,即單個彙總片段將會是不完整的。因此,聚合函式sum()和GROUP BY子句應該在(SELECT)查詢語句中被使用,如上面的例子。

彙總的通用規則

  • 列中數值型別的值會被彙總,進行sum操作。這些列的集合在引數columns中被定義。
  • 如果用於彙總的所有列中的值均為0,則該行會被刪除。
  • 如果列不在主鍵中且無法被彙總,則會在現有的值中任選一個。
  • 主鍵所在的列中的值不會被彙總。

AggregateFunction 列中的彙總

對於AggregateFunction型別的列,ClickHouse根據對應函式表現為AggregatingMergeTree引擎的聚合。

巢狀結構資料的處理

表中可以具有以特殊方式處理的巢狀資料結構。

如果巢狀表的名稱以 Map 結尾,並且包含至少兩個符合以下條件的列:

  • 第一列是數值型別(Int,Date,DateTime),稱之為key,
  • 其他的列是可計算的(Int,Float32/64),稱之為(values...),

然後這個巢狀表會被解釋為一個key=>(values...)的對映,當合並它們的行時,兩個資料集中的元素會被根據key合併為相應的(values...)的彙總值。如下面的例子。

[(1, 100)] + [(2, 150)] -> [(1, 100), (2, 150)]
[(1, 100)] + [(1, 150)] -> [(1, 250)]
[(1, 100)] + [(1, 150), (2, 150)] -> [(1, 250), (2, 150)]
[(1, 100), (2, 150)] + [(1, -100)] -> [(2, 150)]

請求資料時,使用sumMap(key,value)函式來對Map進行聚合。對於巢狀資料結構,你無需在列的元組中指定列以進行彙總。

資料分享

ClickHouse經典中文文件分享

參考文章

相關文章