跳至主要内容
跳至主要内容

AggregatingMergeTree 表引擎

该引擎继承自 MergeTree,改变了数据分片合并的逻辑。ClickHouse 会用单个行(在单个数据分片内)替换具有相同主键(或者更准确地说,具有相同的 排序键)的所有行,该行存储聚合函数状态的组合。

你可以使用 AggregatingMergeTree 表进行增量数据聚合,包括聚合物化视图。

你可以在下面的视频中看到如何使用 AggregatingMergeTree 和 Aggregate 函数的示例

该引擎处理以下类型的列

如果它能将行数减少几个数量级,那么使用 AggregatingMergeTree 是合适的。

创建表

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

有关请求参数的描述,请参阅 请求描述

查询子句

创建 AggregatingMergeTree 表时,需要与创建 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 [=] AggregatingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity)

所有参数的含义与 MergeTree 中的相同。

SELECT 和 INSERT

要插入数据,请使用带有聚合 -State- 函数的 INSERT SELECT 查询。从 AggregatingMergeTree 表中选择数据时,使用 GROUP BY 子句和与插入数据时相同的聚合函数,但使用 -Merge 后缀。

SELECT 查询的结果中,所有 ClickHouse 输出格式的 AggregateFunction 类型的值都具有特定于实现的二进制表示形式。例如,如果你将数据转储到 TabSeparated 格式的 SELECT 查询中,则可以使用 INSERT 查询将该转储加载回去。

聚合物化视图示例

以下示例假定你有一个名为 test 的数据库。如果它不存在,请使用以下命令创建它

CREATE DATABASE test;

现在创建表 test.visits,其中包含原始数据

CREATE TABLE test.visits
 (
    StartDate DateTime64 NOT NULL,
    CounterID UInt64,
    Sign Nullable(Int32),
    UserID Nullable(Int32)
) ENGINE = MergeTree ORDER BY (StartDate, CounterID);

接下来,你需要一个 AggregatingMergeTree 表,它将存储 AggregationFunction,用于跟踪访问总数和唯一用户数。

创建一个 AggregatingMergeTree 物化视图,它监视 test.visits 表,并使用 AggregateFunction 类型

CREATE TABLE test.agg_visits (
    StartDate DateTime64 NOT NULL,
    CounterID UInt64,
    Visits AggregateFunction(sum, Nullable(Int32)),
    Users AggregateFunction(uniq, Nullable(Int32))
)
ENGINE = AggregatingMergeTree() ORDER BY (StartDate, CounterID);

创建一个物化视图,从 test.visits 填充 test.agg_visits

CREATE MATERIALIZED VIEW test.visits_mv TO test.agg_visits
AS SELECT
    StartDate,
    CounterID,
    sumState(Sign) AS Visits,
    uniqState(UserID) AS Users
FROM test.visits
GROUP BY StartDate, CounterID;

将数据插入到 test.visits 表中

INSERT INTO test.visits (StartDate, CounterID, Sign, UserID)
 VALUES (1667446031000, 1, 3, 4), (1667446031000, 1, 6, 3);

数据同时插入到 test.visitstest.agg_visits 中。

要获取聚合数据,请从物化视图 test.visits_mv 执行类似于 SELECT ... GROUP BY ... 的查询

SELECT
    StartDate,
    sumMerge(Visits) AS Visits,
    uniqMerge(Users) AS Users
FROM test.visits_mv
GROUP BY StartDate
ORDER BY StartDate;
┌───────────────StartDate─┬─Visits─┬─Users─┐
│ 2022-11-03 03:27:11.000 │      9 │     2 │
└─────────────────────────┴────────┴───────┘

test.visits 添加另外几条记录,但这次尝试为其中一条记录使用不同的时间戳

INSERT INTO test.visits (StartDate, CounterID, Sign, UserID)
 VALUES (1669446031000, 2, 5, 10), (1667446031000, 3, 7, 5);

再次运行 SELECT 查询,它将返回以下输出

┌───────────────StartDate─┬─Visits─┬─Users─┐
│ 2022-11-03 03:27:11.000 │     16 │     3 │
│ 2022-11-26 07:00:31.000 │      5 │     1 │
└─────────────────────────┴────────┴───────┘

在某些情况下,你可能希望避免在插入时预聚合行,以便将聚合的成本从插入时间转移到合并时间。通常,为了避免错误,需要在物化视图定义中包含未包含在聚合中的列的 GROUP BY 子句。但是,你可以使用 initializeAggregation 函数并设置 optimize_on_insert = 0(默认情况下已启用)来实现这一点。在这种情况下,不再需要使用 GROUP BY

CREATE MATERIALIZED VIEW test.visits_mv TO test.agg_visits
AS SELECT
    StartDate,
    CounterID,
    initializeAggregation('sumState', Sign) AS Visits,
    initializeAggregation('uniqState', UserID) AS Users
FROM test.visits;
注意

在使用 initializeAggregation 时,会为每一行创建一个聚合状态,而无需分组。每一行源数据都会在物化视图中产生一行,实际的聚合发生在 AggregatingMergeTree 合并分片时。只有当 optimize_on_insert = 0 时才成立。

    © . This site is unofficial and not affiliated with ClickHouse, Inc.