跳到主要内容
跳到主要内容

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 可能不会完全汇总所有行(见下文),因此我们在查询中使用聚合函数 sumGROUP 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

对于嵌套数据结构,您无需在用于求和的列元组中指定其列。