SummingMergeTree
该引擎继承自 MergeTree。 区别在于,当合并 SummingMergeTree
表的数据部分时,ClickHouse 会将所有具有相同主键的行(或更准确地说,具有相同排序键的行)替换为一行,其中包含具有数值数据类型的列的汇总值。 如果排序键的构成方式使得单个键值对应于大量行,这将显着减少存储量并加快数据选择速度。
我们建议将该引擎与 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 的参数
columns
columns
- 一个元组,包含将在其中汇总值的列的名称。 可选参数。 这些列必须是数值类型,并且不得在主键中。
如果未指定 columns
,ClickHouse 会汇总主键中不包含的所有数值数据类型列中的值。
查询子句
创建 SummingMergeTree
表时,需要与创建 MergeTree
表时相同的子句。
创建表的已弃用方法
请勿在新项目中使用此方法,如果可能,请将旧项目切换到上述方法。
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(date-column [, sampling_expression], (primary, key), index_granularity, [columns])
除 columns
之外的所有参数都与 MergeTree
中的含义相同。
columns
— 元组,包含将要汇总其值的列的名称。 可选参数。 有关描述,请参见上面的文本。
使用示例
考虑以下表
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
子句。
SELECT key, sum(value) FROM summtt GROUP BY key
┌─key─┬─sum(value)─┐
│ 2 │ 1 │
│ 1 │ 3 │
└─────┴────────────┘
数据处理
当数据插入到表中时,它们会按原样保存。 ClickHouse 定期合并插入的数据部分,这时具有相同主键的行将被汇总,并替换为每个结果数据部分的一行。
ClickHouse 可以合并数据部分,以便不同的结果数据部分可以包含具有相同主键的行,即求和将是不完整的。 因此,在查询中应使用聚合函数 sum() 和 GROUP BY
子句,如上面的示例中所述。
求和的通用规则
数值数据类型列中的值将被汇总。 列的集合由参数 columns
定义。
如果所有用于求和的列中的值都为 0,则该行将被删除。
如果列不在主键中且未被汇总,则从现有值中选择任意值。
主键中的列的值不会被汇总。
AggregateFunction 列中的求和
对于 AggregateFunction 类型 的列,ClickHouse 的行为类似于 AggregatingMergeTree 引擎,根据函数进行聚合。
嵌套结构
表可以具有以特殊方式处理的嵌套数据结构。
如果嵌套表的名称以 Map
结尾,并且它包含至少两列满足以下条件
- 第一列是数值型
(*Int*, Date, DateTime)
或字符串型(String, FixedString)
,我们称之为key
, - 其他列是算术型
(*Int*, Float32/64)
,我们称之为(values...)
,
那么这个嵌套表被解释为 key => (values...)
的映射,并且在合并其行时,两个数据集的元素通过 key
合并,并对相应的 (values...)
进行求和。
示例
DROP TABLE IF EXISTS nested_sum;
CREATE TABLE nested_sum
(
date Date,
site UInt32,
hitsMap Nested(
browser String,
imps UInt32,
clicks UInt32
)
) ENGINE = SummingMergeTree
PRIMARY KEY (date, site);
INSERT INTO nested_sum VALUES ('2020-01-01', 12, ['Firefox', 'Opera'], [10, 5], [2, 1]);
INSERT INTO nested_sum VALUES ('2020-01-01', 12, ['Chrome', 'Firefox'], [20, 1], [1, 1]);
INSERT INTO nested_sum VALUES ('2020-01-01', 12, ['IE'], [22], [0]);
INSERT INTO nested_sum VALUES ('2020-01-01', 10, ['Chrome'], [4], [3]);
OPTIMIZE TABLE nested_sum FINAL; -- emulate merge
SELECT * FROM nested_sum;
┌───────date─┬─site─┬─hitsMap.browser───────────────────┬─hitsMap.imps─┬─hitsMap.clicks─┐
│ 2020-01-01 │ 10 │ ['Chrome'] │ [4] │ [3] │
│ 2020-01-01 │ 12 │ ['Chrome','Firefox','IE','Opera'] │ [20,11,22,5] │ [1,3,0,1] │
└────────────┴──────┴───────────────────────────────────┴──────────────┴────────────────┘
SELECT
site,
browser,
impressions,
clicks
FROM
(
SELECT
site,
sumMap(hitsMap.browser, hitsMap.imps, hitsMap.clicks) AS imps_map
FROM nested_sum
GROUP BY site
)
ARRAY JOIN
imps_map.1 AS browser,
imps_map.2 AS impressions,
imps_map.3 AS clicks;
┌─site─┬─browser─┬─impressions─┬─clicks─┐
│ 12 │ Chrome │ 20 │ 1 │
│ 12 │ Firefox │ 11 │ 3 │
│ 12 │ IE │ 22 │ 0 │
│ 12 │ Opera │ 5 │ 1 │
│ 10 │ Chrome │ 4 │ 3 │
└──────┴─────────┴─────────────┴────────┘
当请求数据时,使用 sumMap(key, value) 函数来聚合 Map
。
对于嵌套数据结构,您无需在用于求和的列元组中指定其列。