clickhouse表引擎-合并树系列

目录

 

1 clickhouse表引擎-合并树系列简介

2 MergeTree引擎

2.1 建表语法

2.2 创建最简单的MergerTree引擎表

2.3 插入数据

2.4 查看目录结构 

2.5 指定分区的 MergeTree 表

2.6 分区合并过程

2.7 指定抽样规则的MergeTree表

3 ReplacingMergeTree引擎

3.1 建表语法

3.2 建表不指定ver参数

3.2.1 执行命令

3.2.2 插入数据

3.2.3 验证保留最后插入的一条

3.3 建表指定ver参数

3.3.1 执行命令

3.3.2 插入数据

3.3.3 验证保留版本号最大的一条

3.4 应用场景

4 CollapsingMergeTree引擎

4.1 建表语法

4.2 创建测试表

4.3 插入数据

4.4 验证折叠更新数据

4.5 算法

4.6 应用场景

5 VersionedCollapsingMergeTree 引擎

5.1 建表语法

5.2 建表

5.3 插入数据

5.4 验证和算法

6 SummingMergeTree引擎

6.1 建表语法

6.2 建表

6.3 插入数据

6.4 测试sum merge

6.5 使用场景

7 AggregatingMergeTree引擎

7.1 AggregatingMergeTree引擎表

7.1.1 建表语法

7.1.2 建一个AggregatingMergeTree引擎表引擎表

7.1.3 直接插入数据

7.1.4 使用 SELECT 和 INSERT 

7.1.5 查询验证

7.1.6 验证后期插入数据的聚合

7.2 AggregatingMergeTree引擎物化视图

7.2.1 建视图前已经存在的数据不能跟踪

7.2.2 可以跟踪建视图后再插入的数据

7.3 使用场景


1 clickhouse表引擎-合并树系列简介

Clickhouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(*MergeTree)中的其他引擎。MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。

主要特点:

① 存储的数据按主键排序。这使得你能够创建一个小型的稀疏索引来加快数据检索。

②  支持数据分区,如果指定了 分区键 的话。在相同数据集和相同结果集的情况下 ClickHouse 中某些带分区的操作会比普通操作更快。查询中指定了分区键时 ClickHouse 会自动截取分区数据。这也有效增加了查询性能。

③ 支持数据副本。ReplicatedMergeTree 系列的表提供了数据副本功能。更多信息,请参阅 数据副本 一节。

④ 支持数据采样。需要的话,你可以给表设置一个采样方法。

2 MergeTree引擎

2.1 建表语法

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]

详解:

① ENGINE - 引擎名和参数。 ENGINE = MergeTree()MergeTree 引擎没有参数。

② ORDER BY — 排序键。可以是一组列的元组或任意的表达式。 例如: ORDER BY (CounterID, EventDate) 。如果没有使用 PRIMARY KEY 显式的指定主键,ClickHouse 会使用排序键作为主键。如果不需要排序,可以使用 ORDER BY tuple(). 参考 选择主键

③ PARTITION BY — 分区键 。要按月分区,可以使用表达式 toYYYYMM(date_column) ,这里的 date_column 是一个 Date 类型的列。分区名的格式会是 "YYYYMM" 。

④ PRIMARY KEY - 主键,如果要 选择与排序键不同的主键,可选。默认情况下主键跟排序键(由 ORDER BY 子句指定)相同。因此,大部分情况下不需要再专门指定一个 PRIMARY KEY 子句。用于指定表数据以何种标准进行分区。分区键可以单个列字段,也可以是通过元祖形式使用的多个列字段,还可以支持使用列表达式。若不声明分区键则clickhouse会生成一个名为all的分区。合理使用分区 可以有效减少查询数据文件的扫描范围。

⑤ SAMPLE BY — 用于抽样的表达式。如果要用抽样表达式,主键中必须包含这个表达式。例如:SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID)) 。

⑥ TTL 指定行存储的持续时间并定义数据片段在硬盘和卷上的移动逻辑的规则列表,可选。表达式中必须存在至少一个 Date 或 DateTime 类型的列,比如:TTL date + INTERVAl 1 DAY 规则的类型 DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'指定了当满足条件(到达指定时间)时所要执行的动作:移除过期的行,还是将数据片段(如果数据片段中的所有行都满足表达式的话)移动到指定的磁盘(TO DISK 'xxx') 或 卷(TO VOLUME 'xxx')。默认的规则是移除(DELETE)。可以在列表中指定多个规则,但最多只能有一个DELETE的规则。更多细节,请查看 表和列的 TTL

⑦ SETTINGS — 控制 MergeTree 行为的额外参数:

  • index_granularity — 索引粒度。索引中相邻的『标记』间的数据行数。默认值,8192 。参考数据存储
  • index_granularity_bytes — 索引粒度,以字节为单位,默认值: 10Mb。如果想要仅按数据行数限制索引粒度, 请设置为0(不建议)。
  • enable_mixed_granularity_parts — 是否启用通过 index_granularity_bytes 控制索引粒度的大小。在19.11版本之前, 只有 index_granularity 配置能够用于限制索引粒度的大小。当从具有很大的行(几十上百兆字节)的表中查询数据时候,index_granularity_bytes 配置能够提升ClickHouse的性能。如果你的表里有很大的行,可以开启这项配置来提升SELECT 查询的性能。
  • use_minimalistic_part_header_in_zookeeper — 是否在 ZooKeeper 中启用最小的数据片段头 。如果设置了 use_minimalistic_part_header_in_zookeeper=1 ,ZooKeeper 会存储更少的数据。更多信息参考『服务配置参数』这章中的 设置描述 。
  • min_merge_bytes_to_use_direct_io — 使用直接 I/O 来操作磁盘的合并操作时要求的最小数据量。合并数据片段时,ClickHouse 会计算要被合并的所有数据的总存储空间。如果大小超过了 min_merge_bytes_to_use_direct_io 设置的字节数,则 ClickHouse 将使用直接 I/O 接口(O_DIRECT 选项)对磁盘读写。如果设置 min_merge_bytes_to_use_direct_io = 0 ,则会禁用直接 I/O。默认值:10 * 1024 * 1024 * 1024 字节。
  • merge_with_ttl_timeout — TTL合并频率的最小间隔时间,单位:秒。默认值: 86400 (1 天)。
  • write_final_mark — 是否启用在数据片段尾部写入最终索引标记。默认值: 1(不建议更改)。
  • merge_max_block_size — 在块中进行合并操作时的最大行数限制。默认值:8192
  • storage_policy — 存储策略。 参见 使用具有多个块的设备进行数据存储.
  • min_bytes_for_wide_part,min_rows_for_wide_part 在数据片段中可以使用Wide格式进行存储的最小字节数/行数。你可以不设置、只设置一个,或全都设置。参考:数据存储

2.2 创建最简单的MergerTree引擎表

建表语句

create table tb_test_MergeTree(`id` Int64,`vipId` Int64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32) engine = MergeTree() ORDER BY (brandId,shopId)

执行

b64d9704419c :) create table tb_test_MergeTree(`id` Int64,`vipId` Int64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32) engine = MergeTree() ORDER BY (brandId,shopId)

CREATE TABLE tb_test_MergeTree
(
    `id` Int64, 
    `vipId` Int64, 
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32
)
ENGINE = MergeTree()
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.044 sec. 

b64d9704419c :)

查看

b64d9704419c :) show tables;

SHOW TABLES

┌─name──────────────┐
│ tb_test_Log       │
│ tb_test_MergeTree │
│ tb_test_StripeLog │
│ tb_test_TinyLog   │
└───────────────────┘

4 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) show create table tb_test_MergeTree

SHOW CREATE TABLE tb_test_MergeTree

┌─statement───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CREATE TABLE liucf_ch_db.tb_test_MergeTree (`id` Int64, `vipId` Int64, `brandId` Int32, `shopId` Int32, `saleDate` Date, `saleMoney` Float32) ENGINE = MergeTree() ORDER BY (brandId, shopId) SETTINGS index_granularity = 8192 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

1 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 

磁盘目录变化

2.3 插入数据

insert into tb_test_MergeTree values (10001,8001,429,6001,'2020-10-01 14:15:23',200.50)
insert into tb_test_MergeTree values (10002,8002,429,6001,'2020-10-02 14:15:23',300.50),(10003,8001,429,6001,'2020-10-02 14:15:23',100.50)

2.4 查看目录结构 

tb_test_MergeTree
├── all_1_1_0
│   ├── brandId.bin
│   ├── brandId.mrk2
│   ├── checksums.txt
│   ├── columns.txt
│   ├── count.txt
│   ├── id.bin
│   ├── id.mrk2
│   ├── primary.idx
│   ├── saleDate.bin
│   ├── saleDate.mrk2
│   ├── saleMoney.bin
│   ├── saleMoney.mrk2
│   ├── shopId.bin
│   ├── shopId.mrk2
│   ├── vipId.bin
│   └── vipId.mrk2
├── detached
└── format_version.txt

可见建表是如果不指定PARTITION BY默认会生成一个all_x_x_x的分区

detached 目录存放着使用 DETACH 语句从表中卸载的片段。损坏的片段不会被删除而是也会移到该目录下。服务器不会去使用detached目录中的数据片段。因此你可以随时添加,删除或修改此目录中的数据 – 在运行 ATTACH 语句前,服务器不会感知到。

查看元数据信息

b64d9704419c :) select * from parts where table='tb_test_MergeTree';

SELECT *
FROM parts
WHERE table = 'tb_test_MergeTree'

┌─partition─┬─name──────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table─────────────┬─engine────┬─disk_name─┬─path──────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ tuple()   │ all_1_1_0 │ Wide      │      1 │     2 │    1 │           491 │                   186 │                      30 │         288 │ 2020-11-10 10:22:54 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ all          │                1 │                1 │     0 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree/all_1_1_0/ │ 4905714359a76926feb423511f18d06f │ 24026952cca8ad85bb6b38798dac951a │ ed4f2b96eecf6163ce254fe3a95ee387      │
└───────────┴───────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴───────────────────┴───────────┴───────────┴───────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

2.5 指定分区的 MergeTree 表

建表语句

create table tb_test_MergeTree_partitions(`id` Int64,`vipId` Int64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32) engine = MergeTree() ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

执行建表 

b64d9704419c :) create table tb_test_MergeTree_partitions(`id` Int64,`vipId` Int64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32) engine = MergeTree() ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_MergeTree_partitions
(
    `id` Int64, 
    `vipId` Int64, 
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32
)
ENGINE = MergeTree()
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.006 sec. 

b64d9704419c :) show create table tb_test_MergeTree_partitions

SHOW CREATE TABLE tb_test_MergeTree_partitions

┌─statement──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CREATE TABLE liucf_ch_db.tb_test_MergeTree_partitions (`id` Int64, `vipId` Int64, `brandId` Int32, `shopId` Int32, `saleDate` Date, `saleMoney` Float32) ENGINE = MergeTree() PARTITION BY (brandId, shopId) ORDER BY (brandId, shopId) SETTINGS index_granularity = 8192 │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

1 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 

文件目录

[root@ds2 liucf_ch_db]# tree tb_test_MergeTree_partitions
tb_test_MergeTree_partitions
├── detached
└── format_version.txt

2.6 分区合并过程

插入数据

b64d9704419c :) insert into tb_test_MergeTree_partitions values (10001,8001,429,6001,'2020-10-01 14:15:23',200.50)

INSERT INTO tb_test_MergeTree_partitions VALUES

Ok.

1 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) insert into tb_test_MergeTree_partitions values (10002,8002,429,6002,'2020-10-02 14:15:23',300.50),(10003,8001,429,6001,'2020-10-02 14:15:23',100.50)

INSERT INTO tb_test_MergeTree_partitions VALUES

Ok.

2 rows in set. Elapsed: 0.037 sec. 

b64d9704419c :) select * from  tb_test_MergeTree_partitions

SELECT *
FROM tb_test_MergeTree_partitions

┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10003 │  8001 │     429 │   6001 │ 2020-10-02 │     100.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10001 │  8001 │     429 │   6001 │ 2020-10-01 │     200.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10002 │  8002 │     429 │   6002 │ 2020-10-02 │     300.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘

3 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) 

磁盘目录

可见分 2次插入3调数据,有3个分区, 

[root@ds2 liucf_ch_db]# tree tb_test_MergeTree_partitions
tb_test_MergeTree_partitions
├── 429-6001_1_1_0
│   ├── brandId.bin
│   ├── brandId.mrk2
│   ├── checksums.txt
│   ├── columns.txt
│   ├── count.txt
│   ├── id.bin
│   ├── id.mrk2
│   ├── minmax_brandId.idx
│   ├── minmax_shopId.idx
│   ├── partition.dat
│   ├── primary.idx
│   ├── saleDate.bin
│   ├── saleDate.mrk2
│   ├── saleMoney.bin
│   ├── saleMoney.mrk2
│   ├── shopId.bin
│   ├── shopId.mrk2
│   ├── vipId.bin
│   └── vipId.mrk2
├── 429-6001_3_3_0
│   ├── brandId.bin
│   ├── brandId.mrk2
│   ├── checksums.txt
│   ├── columns.txt
│   ├── count.txt
│   ├── id.bin
│   ├── id.mrk2
│   ├── minmax_brandId.idx
│   ├── minmax_shopId.idx
│   ├── partition.dat
│   ├── primary.idx
│   ├── saleDate.bin
│   ├── saleDate.mrk2
│   ├── saleMoney.bin
│   ├── saleMoney.mrk2
│   ├── shopId.bin
│   ├── shopId.mrk2
│   ├── vipId.bin
│   └── vipId.mrk2
├── 429-6002_2_2_0
│   ├── brandId.bin
│   ├── brandId.mrk2
│   ├── checksums.txt
│   ├── columns.txt
│   ├── count.txt
│   ├── id.bin
│   ├── id.mrk2
│   ├── minmax_brandId.idx
│   ├── minmax_shopId.idx
│   ├── partition.dat
│   ├── primary.idx
│   ├── saleDate.bin
│   ├── saleDate.mrk2
│   ├── saleMoney.bin
│   ├── saleMoney.mrk2
│   ├── shopId.bin
│   ├── shopId.mrk2
│   ├── vipId.bin
│   └── vipId.mrk2
├── detached
└── format_version.txt

分区目录可以总结为:

查看物理结构:
 
table_name
    |---partition 1
    |    |--checksums.txt
    |    |--columns.txt
    |    |--count.txt
    |    |--primary.idx
    |    |--[column].bin
    |    |--[column].mrk
    |    |--[column].mrk2
          (以上为基础文件)
    |    |--partition.dat
    |    |--minmax_[column].idx
          (以上为使用了分区键的时候生成的文件)
    |    |--skp_idx_[column].idx
    |    |--skp_idx_[column].mrk
          (以上为使用二级索引时候才会生成的文件)
    |---partition_2
    |
    |---partition_n
 
 
 
解释:
1.partition 分区目录
partition_n目录下的各类数据文件都是以分区形式被组织存放的,属于相同分区的数据最终会被合并到同一个分区目录内。
2.checksums.txt:校验文件,使用二进制存储,保存了各类文件的size大小和size的哈希值,用于快速校验文件的完整性和正确性。
3.columns.txt:列信息文件,使用文本文件存储,用于保存分区下的列字段信息。
4.count.txt:计数文件,文本文件存储,用于记录当前数据分区目录下数据的总行数。
5.primary.idx:以及索引文件,使用二进制格式存储。用于存放稀疏索引,一张MergeTree表只能声明一次一级索引
(通过order by或者primary key)。借助稀疏索引在数据查询的时候能够排除主键范围之外的数据文件,从而减少数据扫描范围,加速查询速度。
6.[column].bin:数据文件,使用压缩格式存储,默认使用LZ4压缩格式,用于存储某一列的数据。由于MergeTree采用列式存储,每个列字段都拥有独立的bin数据文件,并以列字段命名。
7.[column].mrk列字段标记,使用二进制格式存储。标记文件中保存了bin文件中数据的偏移量信息,标记文件与稀疏文件对齐,又与bin文件一一对应,所以MergeTree通过标记文件建立了primary.idx稀疏索引与bin数据文件的隐射关系。
首先通过primary.idx找到对应数据的偏移量信息(.mrk),再通过偏移量直接从bin文件中读取数据。由于.mrk标记文件与.bin文件一一对应,所以MergeTree中的每个列字段都会拥有与其对应的.mrk文件。
 
8.[column].mrk2 如使用了自适应大小的索引间隔,则标记文件会以.mrk2命名。工作原理和作用和.mrk标记文件相同。
9.partition.dat和minmax_[column].idx:
若使用了分区键则会额外生成partition.dat和minmax索引文件,均使用二进制格式存储。partition.dat用于保存当前分区下
分区表达式最终生成值,minmax索引文件用于记录当前分区字段对应原始数据的最小值和最大值。
在分区索引作用下,进行数据查询时候能够快速跳过不必要的数据分区目录,从而减少最终需要扫描的数据范围。
10.skp_idx_[column].idx和skp_idx_[column].mrk:
若在建表语句中声明了二级索引则会额外生成相应的二级索引与标记文件,他们同样用二进制存储。
二级索引在clickhouse中又称之为跳数索引,目前拥有minmax,set,ngrambf_v1和tokenbf_v1四种类型。
这些索引的目标和一级稀疏索引相同,为了进一步减少所需要扫描的数据范围,以加速整个查询过程。

元数据也显示3个分区

b64d9704419c :) select * from system.parts where table='tb_test_MergeTree_partitions';

SELECT *
FROM system.parts
WHERE table = 'tb_test_MergeTree_partitions'

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table────────────────────────┬─engine────┬─disk_name─┬─path──────────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_1_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                1 │     0 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6001_1_1_0/ │ 5ae63955e604e81bc6953807bb8a0d90 │ a056aa3b81f706269477195ad7bec7f5 │ ed4f2b96eecf6163ce254fe3a95ee387      │
│ (429,6001) │ 429-6001_3_3_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                3 │                3 │     0 │            3 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6001_3_3_0/ │ 32f9affed43b1e1923f39eb504c14e5d │ a056aa3b81f706269477195ad7bec7f5 │ fd82447c9310b82ae3fc16fc83ad08e4      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6002_2_2_0/ │ 00821628c0d605b2362e419b1b9e1416 │ a1907fcfa6f06f478d357267ced4f5e7 │ d2683ef0e82d3a8805ca211845e3ac85      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴──────────────────────────────┴───────────┴───────────┴───────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

按理说429-6001_1_1_0和429-6001_3_3_0是同一个分区,为什么会在两个分区里呢?是因为,同一批次插入的数据会重新按照partition by 分区写入不会理会之前的批次写入的同样分区的数据,写入后clickhouse会不定时的自动通过内部机制进行合并,合并的过程是会重新生成一个分区,然后把历史分区标志成is not active 状态(也就是active=0),然后再过段时间吧active=0的分区目录删除掉待验证

ClickHouse 会定期的对插入的数据片段进行合并,大约是在插入后15分钟左右。此外,你也可以使用 OPTIMIZE 语句发起一个计划外的合并

为了演示自动合并过程这里强制让clickhouse合并一次分区,

optimize table   tb_test_MergeTree_partitions

注意也可以对单个分区进行合并比如:

OPTIMIZE TABLE visits PARTITION 429-6001;

 执行

b64d9704419c :) optimize table   tb_test_MergeTree_partitions

OPTIMIZE TABLE tb_test_MergeTree_partitions

Ok.

0 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) select * from  tb_test_MergeTree_partitions

SELECT *
FROM tb_test_MergeTree_partitions

┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10002 │  8002 │     429 │   6002 │ 2020-10-02 │     300.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10001 │  8001 │     429 │   6001 │ 2020-10-01 │     200.5 │
│ 10003 │  8001 │     429 │   6001 │ 2020-10-02 │     100.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘

3 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :)

 查看元数据确实是 429-6001_1_1_0 和 429-6001_3_3_0合并成了429-6001_1_3_1 同时把429-6001_1_1_0 和 429-6001_1_3_1的active设置成0 ,429-6002_2_2_0不变

b64d9704419c :) select * from system.parts where table='tb_test_MergeTree_partitions';

SELECT *
FROM system.parts
WHERE table = 'tb_test_MergeTree_partitions'

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table────────────────────────┬─engine────┬─disk_name─┬─path──────────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_1_0 │ Wide      │      0 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 2020-11-10 12:05:16 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                1 │     0 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6001_1_1_0/ │ 5ae63955e604e81bc6953807bb8a0d90 │ a056aa3b81f706269477195ad7bec7f5 │ ed4f2b96eecf6163ce254fe3a95ee387      │
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    2 │           541 │                   212 │                      60 │         288 │ 2020-11-10 12:05:16 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6001_1_3_1/ │ e37f3450a409baaba524e0d8252f211a │ fa7d01d5b36c4a283b4f7216a33905f0 │ ff02a7fb5128f05c1a338492ab6fb03a      │
│ (429,6001) │ 429-6001_3_3_0 │ Wide      │      0 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 2020-11-10 12:05:16 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                3 │                3 │     0 │            3 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6001_3_3_0/ │ 32f9affed43b1e1923f39eb504c14e5d │ a056aa3b81f706269477195ad7bec7f5 │ fd82447c9310b82ae3fc16fc83ad08e4      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6002_2_2_0/ │ 00821628c0d605b2362e419b1b9e1416 │ a1907fcfa6f06f478d357267ced4f5e7 │ d2683ef0e82d3a8805ca211845e3ac85      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴──────────────────────────────┴───────────┴───────────┴───────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

以429-6001_1_3_1为例

  • 429-6001 是分区名称。
  • 1 是数据块的最小编号。
  • 3 是数据块的最大编号。
  • 1 是块级别(即在由块组成的合并树中,该块在树中的深度)

active 列为片段状态。1 代表激活状态;0 代表非激活状态。非激活片段是那些在合并到较大片段之后剩余的源数据片段。损坏的数据片段也表示为非活动状态

然而目录不会那么快删除

等一段时间后不活跃的分区目录就会被删除,在分区的元数据表里也会删除非活跃的分区的数据记录

非激活片段会在合并后的10分钟左右被删除。

磁盘目录删除后,可见只有活跃的分区列表

元数据删除后,可见只有活跃度的分区数据记录

b64d9704419c :) select * from system.parts where table='tb_test_MergeTree_partitions';

SELECT *
FROM system.parts
WHERE table = 'tb_test_MergeTree_partitions'

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table────────────────────────┬─engine────┬─disk_name─┬─path──────────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    2 │           541 │                   212 │                      60 │         288 │ 2020-11-10 12:05:16 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6001_1_3_1/ │ e37f3450a409baaba524e0d8252f211a │ fa7d01d5b36c4a283b4f7216a33905f0 │ ff02a7fb5128f05c1a338492ab6fb03a      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:02:17 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_MergeTree_partitions │ MergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_MergeTree_partitions/429-6002_2_2_0/ │ 00821628c0d605b2362e419b1b9e1416 │ a1907fcfa6f06f478d357267ced4f5e7 │ d2683ef0e82d3a8805ca211845e3ac85      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴──────────────────────────────┴───────────┴───────────┴───────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

2.7 指定抽样规则的MergeTree表

后续补充.....

参考:https://blog.csdn.net/vkingnew/article/details/107090352

3 ReplacingMergeTree引擎

该引擎和 MergeTree 的不同之处在于它会删除排序键值相同的重复项。

数据的去重只会在数据合并期间进行。合并会在后台一个不确定的时间进行,因此你无法预先作出计划。有一些数据可能仍未被处理。尽管你可以调用 OPTIMIZE 语句发起计划外的合并,但请不要依靠它,因为 OPTIMIZE 语句会引发对数据的大量读写。

因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

3.1 建表语法

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

其他语法和MergeTree引擎一直这里不再赘述,只介绍参数ver

ver — 版本列。类型为 UInt*Date 或 DateTime。可选参数。在数据合并的时候,ReplacingMergeTree 从所有具有相同排序键的行中选择一行留下:

  • 如果 ver 列未指定,保留最后一条。
  • 如果 ver 列已指定,保留 ver 值最大的版本。

3.2 建表不指定ver参数

create table tb_test_ReplacingMergeTree_notVer(`id` Int64,`vipId` UInt64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32) engine = ReplacingMergeTree() ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

3.2.1 执行命令

b64d9704419c :) create table tb_test_ReplacingMergeTree_notVer(`id` Int64,`vipId` UInt64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32) engine = ReplacingMergeTree() ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_ReplacingMergeTree_notVer
(
    `id` Int64, 
    `vipId` UInt64, 
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32
)
ENGINE = ReplacingMergeTree()
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :) show tables;

3.2.2 插入数据

insert into tb_test_ReplacingMergeTree_notVer values (10001,8001,429,6001,'2020-10-01 14:15:23',200.50)
insert into tb_test_ReplacingMergeTree_notVer values (10002,8002,429,6002,'2020-10-02 14:15:23',300.50),(10003,8001,429,6001,'2020-10-02 14:15:23',100.50)

查看数据

b64d9704419c :) select * from  tb_test_ReplacingMergeTree_notVer 

SELECT *
FROM tb_test_ReplacingMergeTree_notVer

┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10002 │  8002 │     429 │   6002 │ 2020-10-02 │     300.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10003 │  8001 │     429 │   6001 │ 2020-10-02 │     100.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10001 │  8001 │     429 │   6001 │ 2020-10-01 │     200.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘

3 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :)

从官网可知

PRIMARY KEY - 主键,如果要 选择与排序键不同的主键,可选。默认情况下主键跟排序键(由 ORDER BY 子句指定)相同。因此,大部分情况下不需要再专门指定一个 PRIMARY KEY 子句。

所以上面这个表的primary key 就是 brandId 和 shopId ,从下面的元数据 is_in_primary_key = 1 也能看出来

┌─database────┬─table─────────────────────────────┬─name──────┬─type────┬─default_kind─┬─default_expression─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬─comment─┬─is_in_partition_key─┬─is_in_sorting_key─┬─is_in_primary_key─┬─is_in_sampling_key─┬─compression_codec─┐
│ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ id        │ Int64   │              │                    │                   102 │                      24 │         144 │         │                   0 │                 0 │                 0 │                  0 │                   │
│ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ vipId     │ UInt64  │              │                    │                   102 │                      24 │         144 │         │                   0 │                 0 │                 0 │                  0 │                   │
│ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ brandId   │ Int32   │              │                    │                    90 │                      12 │         144 │         │                   1 │                 1 │                 1 │                  0 │                   │
│ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ shopId    │ Int32   │              │                    │                    90 │                      12 │         144 │         │                   1 │                 1 │                 1 │                  0 │                   │
│ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ saleDate  │ Date    │              │                    │                    84 │                       6 │         144 │         │                   0 │                 0 │                 0 │                  0 │                   │
│ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ saleMoney │ Float32 │              │                    │                    90 │                      12 │         144 │         │                   0 │                 0 │                 0 │                  0 │                   │
└─────────────┴───────────────────────────────────┴───────────┴─────────┴──────────────┴────────────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────┴─────────────────────┴───────────────────┴───────────────────┴────────────────────┴───────────────────┘

所以在clickhouse看来根据primary key = (brandId,shopId)可知 id = 10002 和10003的被视为同一条重复时间,果断时间要删除一条因为我建表的时候没指定ver参数,所以会保留最后插入的一条

那么我猜测根据两天insert into 语句执行的先后顺序合并后应该会保留id=10003的这一条

3.2.3 验证保留最后插入的一条

自动去重时间是不可控的下面使用 Optimize命令强制执行一次模拟自动去重过程

optimize table tb_test_ReplacingMergeTree_notVer

执行和查看数据结果

b64d9704419c :) optimize table tb_test_ReplacingMergeTree_notVer

OPTIMIZE TABLE tb_test_ReplacingMergeTree_notVer

Ok.

0 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :) select * from tb_test_ReplacingMergeTree_notVer;

SELECT *
FROM tb_test_ReplacingMergeTree_notVer

┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10002 │  8002 │     429 │   6002 │ 2020-10-02 │     300.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┐
│ 10003 │  8001 │     429 │   6001 │ 2020-10-02 │     100.5 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┘

2 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :) 

可见确实保留了id=10003这一条后插入的数据,也就是按照排序件(429,6001)删除数据

实际这个过程是先执行分区合并然后再删除重复数据,然后删除分区目录

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table─────────────────────────────┬─engine─────────────┬─disk_name─┬─path───────────────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_1_0 │ Wide      │      0 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:48:39 │ 2020-11-10 13:04:24 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                1 │     0 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ ReplacingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_ReplacingMergeTree_notVer/429-6001_1_1_0/ │ 5ae63955e604e81bc6953807bb8a0d90 │ a056aa3b81f706269477195ad7bec7f5 │ ed4f2b96eecf6163ce254fe3a95ee387      │
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 13:04:24 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ ReplacingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_ReplacingMergeTree_notVer/429-6001_1_3_1/ │ 32f9affed43b1e1923f39eb504c14e5d │ a056aa3b81f706269477195ad7bec7f5 │ fd82447c9310b82ae3fc16fc83ad08e4      │
│ (429,6001) │ 429-6001_3_3_0 │ Wide      │      0 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:48:40 │ 2020-11-10 13:04:24 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                3 │                3 │     0 │            3 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ ReplacingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_ReplacingMergeTree_notVer/429-6001_3_3_0/ │ 32f9affed43b1e1923f39eb504c14e5d │ a056aa3b81f706269477195ad7bec7f5 │ fd82447c9310b82ae3fc16fc83ad08e4      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:48:40 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ ReplacingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_ReplacingMergeTree_notVer/429-6002_2_2_0/ │ 00821628c0d605b2362e419b1b9e1416 │ a1907fcfa6f06f478d357267ced4f5e7 │ d2683ef0e82d3a8805ca211845e3ac85      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴───────────────────────────────────┴────────────────────┴───────────┴────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

最后删除分区磁盘目录保留活跃度分区目录

删除不活跃的分区原数,保留活跃的分区元数据

b64d9704419c :) select * from system.parts where table='tb_test_ReplacingMergeTree_Ver'

SELECT *
FROM system.parts
WHERE table = 'tb_test_ReplacingMergeTree_Ver'

Ok.

0 rows in set. Elapsed: 0.008 sec. 

b64d9704419c :) select * from system.parts where table='tb_test_ReplacingMergeTree_notVer'

SELECT *
FROM system.parts
WHERE table = 'tb_test_ReplacingMergeTree_notVer'

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table─────────────────────────────┬─engine─────────────┬─disk_name─┬─path───────────────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 13:04:24 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ ReplacingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_ReplacingMergeTree_notVer/429-6001_1_3_1/ │ 32f9affed43b1e1923f39eb504c14e5d │ a056aa3b81f706269477195ad7bec7f5 │ fd82447c9310b82ae3fc16fc83ad08e4      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      1 │     2 │    1 │           515 │                   186 │                      30 │         288 │ 2020-11-10 12:48:40 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_ReplacingMergeTree_notVer │ ReplacingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_ReplacingMergeTree_notVer/429-6002_2_2_0/ │ 00821628c0d605b2362e419b1b9e1416 │ a1907fcfa6f06f478d357267ced4f5e7 │ d2683ef0e82d3a8805ca211845e3ac85      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴───────────────────────────────────┴────────────────────┴───────────┴────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

3.3 建表指定ver参数

create table tb_test_ReplacingMergeTree_Ver(`id` Int64,`vipId` UInt64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,version UInt32) engine = ReplacingMergeTree(version) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

3.3.1 执行命令

b64d9704419c :) create table tb_test_ReplacingMergeTree_Ver(`id` Int64,`vipId` UInt64,`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,version UInt32) engine = ReplacingMergeTree(version) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_ReplacingMergeTree_Ver
(
    `id` Int64, 
    `vipId` UInt64, 
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32, 
    `version` UInt32
)
ENGINE = ReplacingMergeTree(version)
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :) 

3.3.2 插入数据

① 先插入一个版本 version=2的数据

insert into tb_test_ReplacingMergeTree_Ver values (10001,8001,429,6001,'2020-10-01 14:15:23',200.50,2)

② 在插入 一条version=1的数据和另外一条key不重复数据一共2条

insert into tb_test_ReplacingMergeTree_Ver values (10002,8002,429,6002,'2020-10-02 14:15:23',300.50,1),(10003,8001,429,6001,'2020-10-02 14:15:23',100.50,1)

 

b64d9704419c :) insert into tb_test_ReplacingMergeTree_Ver values (10002,8002,429,6002,'2020-10-02 14:15:23',300.50,1),(10003,8001,429,6001,'2020-10-02 14:15:23',100.50,1)

INSERT INTO tb_test_ReplacingMergeTree_Ver VALUES

Ok.

2 rows in set. Elapsed: 0.066 sec. 

b64d9704419c :) select * from  tb_test_ReplacingMergeTree_Ver

SELECT *
FROM tb_test_ReplacingMergeTree_Ver

┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─version─┐
│ 10001 │  8001 │     429 │   6001 │ 2020-10-01 │     200.5 │       2 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┴─────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─version─┐
│ 10003 │  8001 │     429 │   6001 │ 2020-10-02 │     100.5 │       1 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┴─────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─version─┐
│ 10002 │  8002 │     429 │   6002 │ 2020-10-02 │     300.5 │       1 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┴─────────┘

3 rows in set. Elapsed: 0.011 sec. 

b64d9704419c :) 

3.3.3 验证保留版本号最大的一条

自动去重时间是不可控的下面使用 Optimize命令强制执行一次模拟自动去重过程

b64d9704419c :) optimize table tb_test_ReplacingMergeTree_Ver

OPTIMIZE TABLE tb_test_ReplacingMergeTree_Ver

Ok.

0 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :) select * from  tb_test_ReplacingMergeTree_Ver

SELECT *
FROM tb_test_ReplacingMergeTree_Ver

┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─version─┐
│ 10002 │  8002 │     429 │   6002 │ 2020-10-02 │     300.5 │       1 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┴─────────┘
┌────id─┬─vipId─┬─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─version─┐
│ 10001 │  8001 │     429 │   6001 │ 2020-10-01 │     200.5 │       2 │
└───────┴───────┴─────────┴────────┴────────────┴───────────┴─────────┘

2 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 

可见对于id=10001和id=10003的这两条因为key=(429,6001)相同被去重了只保留了version=2的版本号大的一条

同样上,不活跃的分区目录和分区元数据信息也会过段时间删掉

3.4 应用场景

 在数据过多重复场景对数据进行去重

数据的去重只会在数据合并期间进行。合并会在后台一个不确定的时间进行,因此你无法预先作出计划。有一些数据可能仍未被处理。尽管你可以调用 OPTIMIZE 语句发起计划外的合并,但请不要依靠它,因为 OPTIMIZE 语句会引发对数据的大量读写。因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

4 CollapsingMergeTree引擎

按照官网说法,该引擎继承于 MergeTree,并在数据块合并算法中添加了折叠行的逻辑。CollapsingMergeTree 会异步的删除(折叠)这些除了特定列 Sign 有 1 和 -1 的值以外,其余所有字段的值都相等的成对的行。没有成对的行会被保留。更多的细节请看本文的折叠部分。也就是说CollapsingMergeTree引擎有个状态列sign,这个值1为”状态”行,-1为”取消”行,对于数据只关心状态列为状态的数据,不关心状态列为取消的数据

4.1 建表语法

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

CollapsingMergeTree 参数

  • sign — 类型列的名称: 1 是«状态»行,-1 是«取消»行。
  • 列数据类型 — Int8。其他数据类型会报错,比如 Int32报错:Code: 169. DB::Exception: Received from xx.xx.x.x:9000. DB::Exception: Sign column (sign) for storage CollapsingMergeTree must have type Int8. Provided column of type Int32..
  • 参数必填项。如果不填建表报错:Code: 42. DB::Exception: Received from xx.xx.x.x:9000. DB::Exception: With extended storage definition syntax storage CollapsingMergeTree requires 1 parameters: 
    sign column

子句

创建 CollapsingMergeTree 表时,需要与创建 MergeTree 表时相同的子句

4.2 创建测试表

create table tb_test_CollapsingMergeTree(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,sign Int8) engine = CollapsingMergeTree(sign) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

执行命令

b64d9704419c :) create table tb_test_CollapsingMergeTree(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,sign Int8) engine = CollapsingMergeTree(sign) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_CollapsingMergeTree
(
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32, 
    `sign` Int8
)
ENGINE = CollapsingMergeTree(sign)
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.006 sec. 

b64d9704419c :) 

磁盘目录结构

[root@ds2 liucf_ch_db]# tree tb_test_CollapsingMergeTree
tb_test_CollapsingMergeTree
├── detached
└── format_version.txt

1 directory, 1 file
[root@ds2 liucf_ch_db]#

4.3 插入数据

① 2020-10-01 14:15:23 品牌429 门店 6001 累计销售金额200.50元

insert into tb_test_CollapsingMergeTree values (429,6001,'2020-10-01 14:15:23',200.50,1)

数据目录变化,和上面讲的类似

[root@ds2 liucf_ch_db]# tree tb_test_CollapsingMergeTree
tb_test_CollapsingMergeTree
├── 429-6001_1_1_0
│   ├── brandId.bin
│   ├── brandId.mrk2
│   ├── checksums.txt
│   ├── columns.txt
│   ├── count.txt
│   ├── minmax_brandId.idx
│   ├── minmax_shopId.idx
│   ├── partition.dat
│   ├── primary.idx
│   ├── saleDate.bin
│   ├── saleDate.mrk2
│   ├── saleMoney.bin
│   ├── saleMoney.mrk2
│   ├── shopId.bin
│   ├── shopId.mrk2
│   ├── sign.bin
│   └── sign.mrk2
├── detached
└── format_version.txt

② 2020-10-02 14:15:23 新增门店6002信息,同时要更新6001门店的累计销售金额为500.50 需要插入3条数据

insert into tb_test_CollapsingMergeTree values (429,6002,'2020-10-02 14:15:23',300.50,1),(429,6001,'2020-10-01 14:15:23',200.50,-1),(429,6001,'2020-10-02 14:15:23',500.50,1)

执行命令和查询验证

b64d9704419c :) insert into tb_test_CollapsingMergeTree values (429,6002,'2020-10-02 14:15:23',300.50,1),(429,6001,'2020-10-01 14:15:23',200.50,-1),(429,6001,'2020-10-02 14:15:23',500.50,1)

INSERT INTO tb_test_CollapsingMergeTree VALUES

Ok.

3 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :) select * from tb_test_CollapsingMergeTree;

SELECT *
FROM tb_test_CollapsingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │    1 │
└─────────┴────────┴────────────┴───────────┴──────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │   -1 │
│     429 │   6001 │ 2020-10-02 │     500.5 │    1 │
└─────────┴────────┴────────────┴───────────┴──────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │    1 │
└─────────┴────────┴────────────┴───────────┴──────┘

4 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :)

目录结构

4.4 验证折叠更新数据

使用命令

optimize table tb_test_CollapsingMergeTree

执行命令然后查看数据

b64d9704419c :) optimize table tb_test_CollapsingMergeTree

OPTIMIZE TABLE tb_test_CollapsingMergeTree

Ok.

0 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) select * from tb_test_CollapsingMergeTree;

SELECT *
FROM tb_test_CollapsingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │    1 │
└─────────┴────────┴────────────┴───────────┴──────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┐
│     429 │   6001 │ 2020-10-02 │     500.5 │    1 │
└─────────┴────────┴────────────┴───────────┴──────┘

2 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :)

可见两条 -1 和 1 重复的两条数据被删除了,折叠更新过程伴随有分区数据的移动,分区429-6001_1_1_0和429-6001_3_3_0被标记为不活跃的分区

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table───────────────────────┬─engine──────────────┬─disk_name─┬─path─────────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_1_0 │ Wide      │      0 │     2 │    1 │           426 │                   145 │                      15 │         240 │ 2020-11-11 07:36:12 │ 2020-11-11 07:44:46 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                1 │     0 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_CollapsingMergeTree │ CollapsingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_CollapsingMergeTree/429-6001_1_1_0/ │ fd66c2b08e2156cda239c2c491ccc0ef │ e33583b1cf3fec7887383dc5a7557afc │ 0bf2ccbfecafdf1496a86fbe9174fc5a      │
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    1 │           426 │                   145 │                      15 │         240 │ 2020-11-11 07:44:46 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_CollapsingMergeTree │ CollapsingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_CollapsingMergeTree/429-6001_1_3_1/ │ 1b16574b6e2d440909456ddbd5b1d107 │ e33583b1cf3fec7887383dc5a7557afc │ 3702132f7a11c36ce7204f673f03b7c6      │
│ (429,6001) │ 429-6001_3_3_0 │ Wide      │      0 │     2 │    2 │           441 │                   160 │                      30 │         240 │ 2020-11-11 07:41:00 │ 2020-11-11 07:44:46 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                3 │                3 │     0 │            3 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_CollapsingMergeTree │ CollapsingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_CollapsingMergeTree/429-6001_3_3_0/ │ 60d3bac1edb7b589fec37ed4c08a62be │ d509e3550750d27e7d6f987b5ca30bb9 │ e710a24eb4233a11453b76cbeb855ddb      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      1 │     2 │    1 │           426 │                   145 │                      15 │         240 │ 2020-11-11 07:41:00 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_CollapsingMergeTree │ CollapsingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_CollapsingMergeTree/429-6002_2_2_0/ │ 260b8f0ae3ae3901a8abff80f8b7b3e1 │ 825c8b7f093cad6c6ebf615dfa301f70 │ d5f2e958dd82a16b148df5da044ee6c2      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴─────────────────────────────┴─────────────────────┴───────────┴──────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

过段时间不活跃的分区信息和目录会自动被清除

4.5 算法

当 ClickHouse 合并数据片段时,每组具有相同主键的连续行被减少到不超过两行,一行 Sign = 1(«状态»行),另一行 Sign = -1 («取消»行),换句话说,数据项被折叠了。

对每个结果的数据部分 ClickHouse 保存:

1. 第一个«取消»和最后一个«状态»行,如果«状态»和«取消»行的数量匹配和最后一个行是«状态»行
2. 最后一个«状态»行,如果«状态»行比«取消»行多一个或一个以上。
3. 第一个«取消»行,如果«取消»行比«状态»行多一个或一个以上。
4. 没有行,在其他所有情况下。

    合并会继续,但是 ClickHouse 会把此情况视为逻辑错误并将其记录在服务日志中。这个错误会在相同的数据被插入超过一次时出现。

因此,折叠不应该改变统计数据的结果。
变化逐渐地被折叠,因此最终几乎每个对象都只剩下了最后的状态。

Sign 是必须的因为合并算法不保证所有有相同主键的行都会在同一个结果数据片段中,甚至是在同一台物理服务器上。ClickHouse 用多线程来处理 SELECT 请求,所以它不能预测结果中行的顺序。如果要从 CollapsingMergeTree 表中获取完全«折叠»后的数据,则需要聚合。

要完成折叠,请使用 GROUP BY 子句和用于处理符号的聚合函数编写请求。例如,要计算数量,使用 sum(Sign) 而不是 count()。要计算某物的总和,使用 sum(Sign * x) 而不是 sum(x),并添加 HAVING sum(Sign) > 0 子句。

聚合体 count,sum 和 avg 可以用这种方式计算。如果一个对象至少有一个未被折叠的状态,则可以计算 uniq 聚合。min 和 max 聚合无法计算,因为 CollaspingMergeTree 不会保存折叠状态的值的历史记录。

如果你需要在不进行聚合的情况下获取数据(例如,要检查是否存在最新值与特定条件匹配的行),你可以在 FROM 从句中使用 FINAL 修饰符。这种方法显然是更低效的

4.6 应用场景

大数据中对于数据更新很难做到,比如统计一个网站的在用户数,更多场景都是选择用记录每个点的数据,再对数据进行一定聚合查询。而clickhouse通过CollapsingMergeTree就可以实现,所以使得CollapsingMergeTree大部分用于OLAP场景

这种方法的特殊属性

  1. 写入的程序应该记住对象的状态从而可以取消它。«取消»字符串应该是«状态»字符串的复制,除了相反的 Sign。它增加了存储的初始数据的大小,但使得写入数据更快速。
  2. 由于写入的负载,列中长的增长阵列会降低引擎的效率。数据越简单,效率越高。
  3. SELECT 的结果很大程度取决于对象变更历史的一致性。在准备插入数据时要准确。在不一致的数据中会得到不可预料的结果,例如,像会话深度这种非负指标的负值。

5 VersionedCollapsingMergeTree 引擎

这个引擎和CollapsingMergeTree差不多,只是对CollapsingMergeTree引擎加了一个版本,比如可以适用于非实时用户在线统计,统计每个节点用户在在线业务

这个引擎:

  • 允许快速写入不断变化的对象状态。
  • 删除后台中的旧对象状态。 这显着降低了存储体积。

引擎继承自 MergeTree 并将折叠行的逻辑添加到合并数据部分的算法中。 VersionedCollapsingMergeTree 用于相同的目的 折叠树 但使用不同的折叠算法,允许以多个线程的任何顺序插入数据。 特别是, Version 列有助于正确折叠行,即使它们以错误的顺序插入。 相比之下, CollapsingMergeTree 只允许严格连续插入。

 

5.1 建表语法

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

引擎参数

VersionedCollapsingMergeTree(sign, version)
  • sign — 指定行类型的列名: 1 是一个 “state” 行, -1 是一个 “cancel” 划

    列数据类型应为 Int8.

  • version — 指定对象状态版本的列名。

    列数据类型应为 UInt*.

  • 参数是必须的,否则报错:Code: 42. DB::Exception: Received from xx.xx.xx.xx:9000. DB::Exception: With extended storage definition syntax storage VersionedCollapsingMergeTree requires 2 parameters: 
    sign column,
    version

查询 Clauses

当创建一个 VersionedCollapsingMergeTree 表时,跟创建一个 MergeTree表的时候需要相同 Clause

5.2 建表

create table tb_test_VersionedCollapsingMergeTree(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,sign Int8,version UInt32) engine = VersionedCollapsingMergeTree(sign,version) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

执行命令

b64d9704419c :) create table tb_test_VersionedCollapsingMergeTree(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,sign Int8,version UInt32) engine = VersionedCollapsingMergeTree(sign,version) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_VersionedCollapsingMergeTree
(
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32, 
    `sign` Int8, 
    `version` UInt32
)
ENGINE = VersionedCollapsingMergeTree(sign, version)
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :)

5.3 插入数据

insert into tb_test_VersionedCollapsingMergeTree values (429,6001,'2020-10-01 14:15:23',200.50,1,1)
insert into tb_test_VersionedCollapsingMergeTree values (429,6002,'2020-10-02 14:15:23',300.50,1,1),(429,6001,'2020-10-01 14:15:23',200.50,-1,2),(429,6001,'2020-10-02 14:15:23',500.50,1,3)

查看数据

b64d9704419c :) select * from tb_test_VersionedCollapsingMergeTree;

SELECT *
FROM tb_test_VersionedCollapsingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │   -1 │       2 │
│     429 │   6001 │ 2020-10-02 │     500.5 │    1 │       3 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │    1 │       1 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │    1 │       1 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘

4 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :) 

5.4 验证和算法

模拟合并

optimize table tb_test_VersionedCollapsingMergeTree

 

OPTIMIZE TABLE tb_test_VersionedCollapsingMergeTree

Ok.

0 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) select * from tb_test_VersionedCollapsingMergeTree;

SELECT *
FROM tb_test_VersionedCollapsingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │    1 │       1 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │    1 │       1 │
│     429 │   6001 │ 2020-10-01 │     200.5 │   -1 │       2 │
│     429 │   6001 │ 2020-10-02 │     500.5 │    1 │       3 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘

4 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 

可见虽然sign 满足 1 和 -1 的配对但是version不一致是不符删除的,针对这个如果想合并掉我们试试掺入下面的数

insert into tb_test_VersionedCollapsingMergeTree values (429,6002,'2020-10-03 14:15:23',600.50,1,2),(429,6002,'2020-10-02 14:15:23',300.50,-1,1)
b64d9704419c :) select * from tb_test_VersionedCollapsingMergeTree;

SELECT *
FROM tb_test_VersionedCollapsingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │    1 │       1 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │    1 │       1 │
│     429 │   6001 │ 2020-10-01 │     200.5 │   -1 │       2 │
│     429 │   6001 │ 2020-10-02 │     500.5 │    1 │       3 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │   -1 │       1 │
│     429 │   6002 │ 2020-10-03 │     600.5 │    1 │       2 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘

6 rows in set. Elapsed: 0.006 sec. 

b64d9704419c :) 

再执行一次

optimize table tb_test_VersionedCollapsingMergeTree

b64d9704419c :) optimize table tb_test_VersionedCollapsingMergeTree

OPTIMIZE TABLE tb_test_VersionedCollapsingMergeTree

Ok.

0 rows in set. Elapsed: 0.007 sec. 

b64d9704419c :) select * from tb_test_VersionedCollapsingMergeTree;

SELECT *
FROM tb_test_VersionedCollapsingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │    1 │       1 │
│     429 │   6001 │ 2020-10-01 │     200.5 │   -1 │       2 │
│     429 │   6001 │ 2020-10-02 │     500.5 │    1 │       3 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─sign─┬─version─┐
│     429 │   6002 │ 2020-10-03 │     600.5 │    1 │       2 │
└─────────┴────────┴────────────┴───────────┴──────┴─────────┘

4 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) 

可见shopid=6002的门店的数据被合并掉了

算法

当ClickHouse合并数据部分时,它会删除具有相同主键和版本但 Sign值不同的一对行. 行的顺序并不重要。

当ClickHouse插入数据时,它会按主键对行进行排序。 如果 Version 列不在主键中,ClickHouse将其隐式添加到主键作为最后一个字段并使用它进行排序。

6 SummingMergeTree引擎

该引擎继承自 MergeTree。区别在于,当合并 SummingMergeTree 表的数据片段时,ClickHouse 会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值。如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度,对于不可加的列则会在现有的值中任选一个。

6.1 建表语法

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`,ClickHouse 会把所有不在主键中的数值类型的列都进行汇总。
    

子句

创建 SummingMergeTree 表时,需要与创建 MergeTree 表时相同的子句

6.2 建表

根据 key (brandId,shopId) 对 saleMoney和saleNum进行聚合

create table tb_test_SummingMergeTree(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,saleNum Int32) engine = SummingMergeTree ((saleMoney,saleNum)) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

执行

b64d9704419c :) create table tb_test_SummingMergeTree(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,saleNum Int32) engine = SummingMergeTree ((saleMoney,saleNum)) ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_SummingMergeTree
(
    `brandId` Int32, 
    `shopId` Int32, 
    `saleDate` Date, 
    `saleMoney` Float32, 
    `saleNum` Int32
)
ENGINE = SummingMergeTree((saleMoney, saleNum))
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.006 sec. 

b64d9704419c :)

6.3 插入数据

insert into tb_test_SummingMergeTree values (429,6001,'2020-10-01 14:15:23',200.50,10)
insert into tb_test_SummingMergeTree values (429,6002,'2020-10-02 14:15:23',300.50,20),(429,6001,'2020-10-02 14:15:23',200.50,10),(429,6001,'2020-10-03 14:15:23',500.50,10)
b64d9704419c :) select * from  tb_test_SummingMergeTree

SELECT *
FROM tb_test_SummingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │      20 │
└─────────┴────────┴────────────┴───────────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6001 │ 2020-10-02 │     200.5 │      10 │
│     429 │   6001 │ 2020-10-03 │     500.5 │      10 │
└─────────┴────────┴────────────┴───────────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │      10 │
└─────────┴────────┴────────────┴───────────┴─────────┘

4 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 

6.4 测试sum merge

等待后台自动merge或通过optimize table tb_test_SummingMergeTree命令手动Merge后查询

b64d9704419c :) optimize table tb_test_SummingMergeTree

OPTIMIZE TABLE tb_test_SummingMergeTree

Ok.

0 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) select * from  tb_test_SummingMergeTree

SELECT *
FROM tb_test_SummingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │      20 │
└─────────┴────────┴────────────┴───────────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6001 │ 2020-10-01 │     901.5 │      30 │
└─────────┴────────┴────────────┴───────────┴─────────┘

2 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 

可见完成了合并

当数据被插入到表中时,他们将被原样保存。ClickHouse 定期合并插入的数据片段,并在这个时候对所有具有相同主键的行中的列进行汇总,将这些行替换为包含汇总数据的一行记录。

再插入一条

insert into tb_test_SummingMergeTree values (429,6002,'2020-10-02 14:15:23',-300.50,-20)
b64d9704419c :) select * from  tb_test_SummingMergeTree

SELECT *
FROM tb_test_SummingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6002 │ 2020-10-02 │     300.5 │      20 │
└─────────┴────────┴────────────┴───────────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6002 │ 2020-10-02 │    -300.5 │     -20 │
└─────────┴────────┴────────────┴───────────┴─────────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6001 │ 2020-10-01 │     901.5 │      30 │
└─────────┴────────┴────────────┴───────────┴─────────┘

3 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) 

再手动触发一次合并

b64d9704419c :) optimize table tb_test_SummingMergeTree

OPTIMIZE TABLE tb_test_SummingMergeTree

Ok.

0 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) select * from  tb_test_SummingMergeTree

SELECT *
FROM tb_test_SummingMergeTree

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleNum─┐
│     429 │   6001 │ 2020-10-01 │     901.5 │      30 │
└─────────┴────────┴────────────┴───────────┴─────────┘

1 rows in set. Elapsed: 0.002 sec. 

b64d9704419c :) 
b64d9704419c :) select * from system.parts where table='tb_test_SummingMergeTree'

SELECT *
FROM system.parts
WHERE table = 'tb_test_SummingMergeTree'

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table────────────────────┬─engine───────────┬─disk_name─┬─path──────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    1 │           429 │                   148 │                      18 │         240 │ 2020-11-11 10:37:18 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_SummingMergeTree │ SummingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_SummingMergeTree/429-6001_1_3_1/ │ 6e44378ccbc984937371925a82a95328 │ f3f9c5dce1afbb78722226cad004b4dc │ a27b6982af402314c039fe91f37e06bc      │
│ (429,6002) │ 429-6002_2_2_0 │ Wide      │      0 │     2 │    1 │           429 │                   148 │                      18 │         240 │ 2020-11-11 10:32:00 │ 2020-11-11 10:51:44 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                2 │     0 │            2 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_SummingMergeTree │ SummingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_SummingMergeTree/429-6002_2_2_0/ │ 2b1a9b55c6778f1dc03f72642feee88d │ f6845a7591f3dc155b6735f075b682d1 │ 748dd0e206ea8293ef69e330f2b0489b      │
│ (429,6002) │ 429-6002_2_4_1 │ Wide      │      1 │     0 │    0 │            25 │                     0 │                       0 │           0 │ 2020-11-11 10:51:44 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                4 │     1 │            2 │                           0 │                                     0 │         0 │ liucf_ch_db │ tb_test_SummingMergeTree │ SummingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_SummingMergeTree/429-6002_2_4_1/ │ ce47c0c0cf9bffa657a065ae3755621c │ 64aa849c9f729e351ac2c82b2f373927 │ 3cf7e887484e39aa49273780422ff52b      │
│ (429,6002) │ 429-6002_4_4_0 │ Wide      │      0 │     2 │    1 │           429 │                   148 │                      18 │         240 │ 2020-11-11 10:50:34 │ 2020-11-11 10:51:44 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                4 │                4 │     0 │            4 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_SummingMergeTree │ SummingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_SummingMergeTree/429-6002_4_4_0/ │ fecec7d3b11e6e966af2065f77f83198 │ f6845a7591f3dc155b6735f075b682d1 │ 4cadd46275424fdab1805bb99b632789      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴──────────────────────────┴──────────────────┴───────────┴───────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

 

可见 所有聚合字段聚合后的值变成了0 然后合并的结果插入到429-6002_2_4_1分区了

过段时间不活跃的分区目录会被删除,分区元数据也会被删除。但是数据是0的(比如(429,6002))不会被删除如下面的429-6002_2_4_1

 

b64d9704419c :) select * from system.parts where table='tb_test_SummingMergeTree'

SELECT *
FROM system.parts
WHERE table = 'tb_test_SummingMergeTree'

┌─partition──┬─name───────────┬─part_type─┬─active─┬─marks─┬─rows─┬─bytes_on_disk─┬─data_compressed_bytes─┬─data_uncompressed_bytes─┬─marks_bytes─┬───modification_time─┬─────────remove_time─┬─refcount─┬───min_date─┬───max_date─┬────────────min_time─┬────────────max_time─┬─partition_id─┬─min_block_number─┬─max_block_number─┬─level─┬─data_version─┬─primary_key_bytes_in_memory─┬─primary_key_bytes_in_memory_allocated─┬─is_frozen─┬─database────┬─table────────────────────┬─engine───────────┬─disk_name─┬─path──────────────────────────────────────────────────────────────────────────┬─hash_of_all_files────────────────┬─hash_of_uncompressed_files───────┬─uncompressed_hash_of_compressed_files─┐
│ (429,6001) │ 429-6001_1_3_1 │ Wide      │      1 │     2 │    1 │           429 │                   148 │                      18 │         240 │ 2020-11-11 10:37:18 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6001     │                1 │                3 │     1 │            1 │                          16 │                                  8192 │         0 │ liucf_ch_db │ tb_test_SummingMergeTree │ SummingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_SummingMergeTree/429-6001_1_3_1/ │ 6e44378ccbc984937371925a82a95328 │ f3f9c5dce1afbb78722226cad004b4dc │ a27b6982af402314c039fe91f37e06bc      │
│ (429,6002) │ 429-6002_2_4_1 │ Wide      │      1 │     0 │    0 │            25 │                     0 │                       0 │           0 │ 2020-11-11 10:51:44 │ 0000-00-00 00:00:00 │        1 │ 0000-00-00 │ 0000-00-00 │ 0000-00-00 00:00:00 │ 0000-00-00 00:00:00 │ 429-6002     │                2 │                4 │     1 │            2 │                           0 │                                     0 │         0 │ liucf_ch_db │ tb_test_SummingMergeTree │ SummingMergeTree │ default   │ /var/lib/clickhouse/data/liucf_ch_db/tb_test_SummingMergeTree/429-6002_2_4_1/ │ ce47c0c0cf9bffa657a065ae3755621c │ 64aa849c9f729e351ac2c82b2f373927 │ 3cf7e887484e39aa49273780422ff52b      │
└────────────┴────────────────┴───────────┴────────┴───────┴──────┴───────────────┴───────────────────────┴─────────────────────────┴─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────┴────────────┴─────────────────────┴─────────────────────┴──────────────┴──────────────────┴──────────────────┴───────┴──────────────┴─────────────────────────────┴───────────────────────────────────────┴───────────┴─────────────┴──────────────────────────┴──────────────────┴───────────┴───────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────┴──────────────────────────────────┴───────────────────────────────────────┘

 

终结 

列中数值类型的值会被汇总。这些列的集合在参数 columns 中被定义。比如 saleMoney,saleNum

如果用于汇总的所有列中的值均为0,则该行会被删除。如上面例子查不到 汇总列都是0的

如果列不在主键中且无法被汇总,则会在现有的值中任选一个。比如saleDate

主键所在的列中的值不会被汇总。brandId,shopId

6.5 使用场景

对某个字段长期的汇总查询场景

官网推荐将该引擎和 MergeTree 一起使用。例如,在准备做报告的时候,将完整的数据存储在 MergeTree 表中,并且使用 SummingMergeTree 来存储聚合数据。这种方法可以使你避免因为使用不正确的主键组合方式而丢失有价值的数据。

7 AggregatingMergeTree引擎

 

该引擎继承自 MergeTree,并改变了数据片段的合并逻辑。 ClickHouse 会将相同主键的所有行(在一个数据片段内)替换为单个存储一系列聚合函数状态的行。可以使用 AggregatingMergeTree 表来做增量数据统计聚合,包括物化视图的数据聚合。引擎需使用 AggregateFunction 类型来处理所有列。如果要按一组规则来合并减少行数,则使用 AggregatingMergeTree 是合适的。对于AggregatingMergeTree不能直接使用insert来查询写入数据。一般是用insert select。但更常用的是创建物化视图

创建测试表和数据:

①建表

create table tb_test_MergeTree_basic(`brandId` Int32,`shopId` Int32, `saleDate` Date,saleMoney Float32,saleQty Int32,vipId UInt64) engine = MergeTree () ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId) 

 

b64d9704419c :) select brandId,shopId,sumMerge(saleMoney) saleMoney,sumMerge(saleQty) saleQty,countMerge(saleNum) saleNum,uniqMerge(vipNum)  vipNum from tb_test_AggregatingMergeTree_table group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sumMerge(saleMoney) AS saleMoney, 
    sumMerge(saleQty) AS saleQty, 
    countMerge(saleNum) AS saleNum, 
    uniqMerge(vipNum) AS vipNum
FROM tb_test_AggregatingMergeTree_table
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │       401 │      50 │       2 │      1 │
│     429 │   6001 │      1203 │     120 │       6 │      3 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

2 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) 

② 插入数据

insert into tb_test_MergeTree_basic values (429,6001,'2020-10-01 14:15:23',200.50,10,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-02 14:15:23',200.50,20,10002)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-03 14:15:23',200.50,30,10003)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-04 14:15:23',200.50,10,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-05 14:15:23',200.50,20,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-06 14:15:23',200.50,30,10003)
insert into tb_test_MergeTree_basic values (429,6002,'2020-10-04 14:15:23',200.50,40,10001)
insert into tb_test_MergeTree_basic values (429,6002,'2020-10-05 14:15:23',200.50,10,10001)

后面使用先放着

 

7.1 AggregatingMergeTree引擎表

7.1.1 建表语法

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 表一样的子句

7.1.2 建一个AggregatingMergeTree引擎表引擎表

配合AggregateFunction使用

create table tb_test_AggregatingMergeTree_table(`brandId` Int32,`shopId` Int32, saleMoney AggregateFunction(sum,Float32),saleQty AggregateFunction(sum,Int32),saleNum AggregateFunction(count,UInt8),vipNum AggregateFunction(uniq,UInt64)) engine = AggregatingMergeTree () ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

执行命令

b64d9704419c :) create table tb_test_AggregatingMergeTree_table(`brandId` Int32,`shopId` Int32, saleMoney AggregateFunction(sum,Float32),saleQty AggregateFunction(sum,Int32),saleNum AggregateFunction(count,UInt8),vipNum AggregateFunction(uniq,UInt64)) engine = AggregatingMergeTree () ORDER BY (brandId,shopId) PARTITION BY (brandId,shopId)

CREATE TABLE tb_test_AggregatingMergeTree_table
(
    `brandId` Int32, 
    `shopId` Int32, 
    `saleMoney` AggregateFunction(sum, Float32), 
    `saleQty` AggregateFunction(sum, Int32), 
    `saleNum` AggregateFunction(count, UInt8), 
    `vipNum` AggregateFunction(uniq, UInt64)
)
ENGINE = AggregatingMergeTree()
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId)

Ok.

0 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :)

7.1.3 直接插入数据

 直接用insert

insert into tb_test_AggregatingMergeTree_table values (429,6001,200.50,10,3,2)

报错:类似于 Cannot convert Float64 to AggregateFunction(sum, Float64)

 

b64d9704419c :) insert into tb_test_AggregatingMergeTree_table values (429,6001,200.50,10,3,2)

INSERT INTO tb_test_AggregatingMergeTree_table VALUES


Exception on client:
Code: 53. DB::Exception: Cannot convert Float64 to AggregateFunction(sum, Float64)

Connecting to database liucf_ch_db at 192.168.12.14:9000 as user root.
Connected to ClickHouse server version 20.3.21 revision 54433.

b64d9704419c :) 

7.1.4 使用 SELECT 和 INSERT 

要插入数据,需使用带有 -State- 聚合函数的 INSERT SELECT 语句

insert into tb_test_AggregatingMergeTree_table select brandId,shopId,sumState(saleMoney) saleMoney,sumState(saleQty) saleQty,countState(1) saleNum,uniqState(vipId)  vipNum from tb_test_MergeTree_basic group by brandId,shopId

注意:建表的时候AggregateFunction函数内的数据类型要和basic表要聚合的字段的类型一致不然会报错 

比如 

(1)tb_test_MergeTree_basic: saleMoney Float32 ,tb_test_AggregatingMergeTree_table 表定义时saleMoney  AggregateFunction(sum,Float64)

插入的时候报错:Conversion from AggregateFunction(sum, Float32) to AggregateFunction(sum, Float64) is not supported

(2)使用count时 tb_test_AggregatingMergeTree_table 表定义时AggregateFunction(count,Int32) 

插入时 insert select 语句会报错 Conversion from AggregateFunction(count, UInt8) to AggregateFunction(count, Int32) is not supported

这个问题可以通过类型转换函数来解决

执行

b64d9704419c :) insert into tb_test_AggregatingMergeTree_table select brandId,shopId,sumState(saleMoney) saleMoney,sumState(saleQty) saleQty,countState(1) saleNum,uniqState(vipId)  vipNum from tb_test_MergeTree_basic group by brandId,shopId

INSERT INTO tb_test_AggregatingMergeTree_table SELECT 
    brandId, 
    shopId, 
    sumState(saleMoney) AS saleMoney, 
    sumState(saleQty) AS saleQty, 
    countState(1) AS saleNum, 
    uniqState(vipId) AS vipNum
FROM tb_test_MergeTree_basic
GROUP BY 
    brandId, 
    shopId

↑ Progress: 8.00 rows, 192.00 B (1.69 thousand rows/s., 40.52 KB/s.)  0%Ok.

0 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :) 

7.1.5 查询验证

直接查询只能看到主键和聚合函数AggregateFunction()的别名和乱码

b64d9704419c :) select * from tb_test_AggregatingMergeTree_table

SELECT *
FROM tb_test_AggregatingMergeTree_table

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │ y@        │ 2       │         │ l 
                                                      򞞠 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum───┐
│     429 │   6001 │ ̒@         │ x       │         │ l 
                                                      󷥄³Gw │
└─────────┴────────┴───────────┴─────────┴─────────┴──────────┘

2 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :) 

 

所以正确的查询方式是

从 AggregatingMergeTree 表中查询数据时,需使用 GROUP BY 子句并且要使用与插入时相同的聚合函数,但后缀要改为 -Merge 。

select brandId,shopId,sumMerge(saleMoney) saleMoney,sumMerge(saleQty) saleQty,countMerge(saleNum) saleNum,uniqMerge(vipNum)  vipNum from tb_test_AggregatingMergeTree_table group by brandId,shopId

执行查询

b64d9704419c :) select * from tb_test_MergeTree_basic

SELECT *
FROM tb_test_MergeTree_basic

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6002 │ 2020-10-04 │     200.5 │      40 │ 10001 │
│     429 │   6002 │ 2020-10-05 │     200.5 │      10 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-06 │     200.5 │      30 │ 10003 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │      10 │ 10001 │
│     429 │   6001 │ 2020-10-02 │     200.5 │      20 │ 10002 │
│     429 │   6001 │ 2020-10-03 │     200.5 │      30 │ 10003 │
│     429 │   6001 │ 2020-10-04 │     200.5 │      10 │ 10001 │
│     429 │   6001 │ 2020-10-05 │     200.5 │      20 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘

8 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) select brandId,shopId,sumMerge(saleMoney) saleMoney,sumMerge(saleQty) saleQty,countMerge(saleNum) saleNum,uniqMerge(vipNum)  vipNum from tb_test_AggregatingMergeTree_table group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sumMerge(saleMoney) AS saleMoney, 
    sumMerge(saleQty) AS saleQty, 
    countMerge(saleNum) AS saleNum, 
    uniqMerge(vipNum) AS vipNum
FROM tb_test_AggregatingMergeTree_table
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │       401 │      50 │       2 │      1 │
│     429 │   6001 │      1203 │     120 │       6 │      3 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

2 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :)

7.1.6 验证后期插入数据的聚合

也就是 insert into tb_test_AggregatingMergeTree_table select brandId,shopId,sumState(saleMoney) saleMoney,sumState(saleQty) saleQty,countState(1) saleNum,uniqState(vipId)  vipNum from tb_test_MergeTree_basic group by brandId,shopId 执行完成之后,又有数据插入到tb_test_MergeTree_basic表是否也能正常聚合

① 插入数据

insert into tb_test_MergeTree_basic values (429,6001,'2020-10-07 14:15:23',200.50,30,10003)
insert into tb_test_MergeTree_basic values (429,6002,'2020-10-07 14:15:23',200.50,40,10002)

b64d9704419c :) select * from tb_test_MergeTree_basic

SELECT *
FROM tb_test_MergeTree_basic

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6002 │ 2020-10-04 │     200.5 │      40 │ 10001 │
│     429 │   6002 │ 2020-10-05 │     200.5 │      10 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6002 │ 2020-10-07 │     200.5 │      40 │ 10002 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-06 │     200.5 │      30 │ 10003 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-07 │     200.5 │      30 │ 10003 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │      10 │ 10001 │
│     429 │   6001 │ 2020-10-02 │     200.5 │      20 │ 10002 │
│     429 │   6001 │ 2020-10-03 │     200.5 │      30 │ 10003 │
│     429 │   6001 │ 2020-10-04 │     200.5 │      10 │ 10001 │
│     429 │   6001 │ 2020-10-05 │     200.5 │      20 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘

② 查询看看能不能自动聚合

结果如下,可见不能把新增的数据聚合过来,

b64d9704419c :) select brandId,shopId,sumMerge(saleMoney) saleMoney,sumMerge(saleQty) saleQty,countMerge(saleNum) saleNum,uniqMerge(vipNum)  vipNum from tb_test_AggregatingMergeTree_table group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sumMerge(saleMoney) AS saleMoney, 
    sumMerge(saleQty) AS saleQty, 
    countMerge(saleNum) AS saleNum, 
    uniqMerge(vipNum) AS vipNum
FROM tb_test_AggregatingMergeTree_table
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │       401 │      50 │       2 │      1 │
│     429 │   6001 │      1203 │     120 │       6 │      3 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

2 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :)

 

7.2 AggregatingMergeTree引擎物化视图

创建一个跟踪tb_test_MergeTree_basic表的物化视图

create materialized view tb_test_AggregatingMergeTree_view ENGINE = AggregatingMergeTree() PARTITION BY (brandId,shopId) ORDER BY (brandId,shopId) as select brandId,shopId,sumState(saleMoney) saleMoney,sumState(saleQty) saleQty,countState(1) saleNum,uniqState(vipId)  vipNum from tb_test_MergeTree_basic group by brandId,shopId

执行命令

b64d9704419c :) create materialized view tb_test_AggregatingMergeTree_view ENGINE = AggregatingMergeTree() PARTITION BY (brandId,shopId) ORDER BY (brandId,shopId) as select brandId,shopId,sumState(saleMoney) saleMoney,sumState(saleQty) saleQty,countState(1) saleNum,uniqState(vipId)  vipNum from tb_test_MergeTree_basic group by brandId,shopId

CREATE MATERIALIZED VIEW tb_test_AggregatingMergeTree_view
ENGINE = AggregatingMergeTree()
PARTITION BY (brandId, shopId)
ORDER BY (brandId, shopId) AS
SELECT 
    brandId, 
    shopId, 
    sumState(saleMoney) AS saleMoney, 
    sumState(saleQty) AS saleQty, 
    countState(1) AS saleNum, 
    uniqState(vipId) AS vipNum
FROM tb_test_MergeTree_basic
GROUP BY 
    brandId, 
    shopId

Ok.

0 rows in set. Elapsed: 0.012 sec. 

b64d9704419c :) 

show table 

可见比普通表多了“.inner.”前缀

目录名称也比普通表多了一些类似乱码的字符

7.2.1 建视图前已经存在的数据不能跟踪

tb_test_MergeTree_basic 表原来已经在创建物化视图的时候已经有数据了现在查一下看看

b64d9704419c :) select * from tb_test_MergeTree_basic 

SELECT *
FROM tb_test_MergeTree_basic

┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6002 │ 2020-10-07 │     200.5 │      40 │ 10002 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6002 │ 2020-10-05 │     200.5 │      10 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-07 │     200.5 │      30 │ 10003 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6002 │ 2020-10-04 │     200.5 │      40 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-01 │     200.5 │      10 │ 10001 │
│     429 │   6001 │ 2020-10-02 │     200.5 │      20 │ 10002 │
│     429 │   6001 │ 2020-10-03 │     200.5 │      30 │ 10003 │
│     429 │   6001 │ 2020-10-04 │     200.5 │      10 │ 10001 │
│     429 │   6001 │ 2020-10-05 │     200.5 │      20 │ 10001 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘
┌─brandId─┬─shopId─┬───saleDate─┬─saleMoney─┬─saleQty─┬─vipId─┐
│     429 │   6001 │ 2020-10-06 │     200.5 │      30 │ 10003 │
└─────────┴────────┴────────────┴───────────┴─────────┴───────┘

执行一次optimize table tb_test_AggregatingMergeTree_view

再查tb_test_AggregatingMergeTree_view视图

b64d9704419c :) select * from tb_test_AggregatingMergeTree_view

SELECT *
FROM tb_test_AggregatingMergeTree_view

Ok.

0 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :)

可见没有跟踪建表之前的已经存在的数据

7.2.2 可以跟踪建视图后再插入的数据

① 插入2条数据

insert into tb_test_MergeTree_basic values (429,6001,'2020-10-08 14:15:23',200.50,30,10003)
insert into tb_test_MergeTree_basic values (429,6002,'2020-10-08 14:15:23',200.50,40,10002)

② 查看

b64d9704419c :) select * from tb_test_AggregatingMergeTree_view

SELECT *
FROM tb_test_AggregatingMergeTree_view

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6001 │ i@        │         │         │ ³Gw     │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │ i@        │ (       │         │ $a6㞠  │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

2 rows in set. Elapsed: 0.008 sec. 

b64d9704419c :)

③ 聚合的结果

b64d9704419c :) select brandId,shopId,sumMerge(saleMoney) saleMoney,sumMerge(saleQty) saleQty,countMerge(saleNum) saleNum,uniqMerge(vipNum)  vipNum from tb_test_AggregatingMergeTree_view group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sumMerge(saleMoney) AS saleMoney, 
    sumMerge(saleQty) AS saleQty, 
    countMerge(saleNum) AS saleNum, 
    uniqMerge(vipNum) AS vipNum
FROM tb_test_AggregatingMergeTree_view
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │     200.5 │      40 │       1 │      1 │
│     429 │   6001 │     200.5 │      30 │       1 │      1 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

2 rows in set. Elapsed: 0.005 sec. 

b64d9704419c :)

④ 继续插入新的数据

insert into tb_test_MergeTree_basic values (429,6001,'2020-10-09 14:15:23',200.50,10,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-09 14:15:23',200.50,20,10002)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-09 14:15:23',200.50,30,10003)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-09 14:15:23',200.50,10,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-09 14:15:23',200.50,20,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-09 14:15:23',200.50,30,10003)
insert into tb_test_MergeTree_basic values (429,6002,'2020-10-09 14:15:23',200.50,40,10001)
insert into tb_test_MergeTree_basic values (429,6002,'2020-10-09 14:15:23',200.50,10,10001)
insert into tb_test_MergeTree_basic values (429,6001,'2020-10-10 14:15:23',200.50,10,10001)

⑤ 查看

可见分区没有合并

b64d9704419c :) select * from tb_test_AggregatingMergeTree_view

SELECT *
FROM tb_test_AggregatingMergeTree_view

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6001 │ i@        │         │         │ l 
                                                      򞞠 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6001 │ i@        │         │         │ ³Gw     │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │ i@        │ 
        │         │ l 
                     򞞠 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6001 │ i@        │ 
        │         │ l 
                     򞞠 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │ i@        │ (       │         │ $a6㞠  │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum───┐
│     429 │   6001 │ T@        │ d       │         │ l 
                                                      󷥄³Gw │
└─────────┴────────┴───────────┴─────────┴─────────┴──────────┘
┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │ i@        │ (       │         │ l 
                                                      򞞠 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

7 rows in set. Elapsed: 0.004 sec. 

b64d9704419c :)

⑥ 观察自动跟踪了

b64d9704419c :) select brandId,shopId,sumMerge(saleMoney) saleMoney,sumMerge(saleQty) saleQty,countMerge(saleNum) saleNum,uniqMerge(vipNum)  vipNum from tb_test_AggregatingMergeTree_view group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sumMerge(saleMoney) AS saleMoney, 
    sumMerge(saleQty) AS saleQty, 
    countMerge(saleNum) AS saleNum, 
    uniqMerge(vipNum) AS vipNum
FROM tb_test_AggregatingMergeTree_view
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─saleMoney─┬─saleQty─┬─saleNum─┬─vipNum─┐
│     429 │   6002 │     601.5 │      90 │       3 │      2 │
│     429 │   6001 │      1604 │     160 │       8 │      3 │
└─────────┴────────┴───────────┴─────────┴─────────┴────────┘

2 rows in set. Elapsed: 0.010 sec. 

b64d9704419c :) 

可见确实已经自动跟踪聚合了

但是只是创建视图后插入的数据才能跟踪,验证SQL 如下

select brandId,shopId,sum(saleMoney),sum(saleQty),count(1),uniq(vipId) from tb_test_MergeTree_basic  where saleDate>='2020-10-08' group by brandId,shopId

执行

b64d9704419c :) select brandId,shopId,sum(saleMoney),sum(saleQty),count(1),uniq(vipId) from tb_test_MergeTree_basic  where saleDate>='2020-10-08' group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sum(saleMoney), 
    sum(saleQty), 
    count(1), 
    uniq(vipId)
FROM tb_test_MergeTree_basic
WHERE saleDate >= '2020-10-08'
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─sum(saleMoney)─┬─sum(saleQty)─┬─count(1)─┬─uniq(vipId)─┐
│     429 │   6002 │          601.5 │           90 │        3 │           2 │
│     429 │   6001 │           1604 │          160 │        8 │           3 │
└─────────┴────────┴────────────────┴──────────────┴──────────┴─────────────┘

2 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) 

创建视图前原来已经存在的数据是不能被跟踪的

下面的这部分值不能被跟踪

select brandId,shopId,sum(saleMoney),sum(saleQty),count(1),uniq(vipId) from tb_test_MergeTree_basic  where saleDate<'2020-10-08' group by brandId,shopId

SELECT 
    brandId, 
    shopId, 
    sum(saleMoney), 
    sum(saleQty), 
    count(1), 
    uniq(vipId)
FROM tb_test_MergeTree_basic
WHERE saleDate < '2020-10-08'
GROUP BY 
    brandId, 
    shopId

┌─brandId─┬─shopId─┬─sum(saleMoney)─┬─sum(saleQty)─┬─count(1)─┬─uniq(vipId)─┐
│     429 │   6002 │          601.5 │           90 │        3 │           2 │
│     429 │   6001 │         1403.5 │          150 │        7 │           3 │
└─────────┴────────┴────────────────┴──────────────┴──────────┴─────────────┘

2 rows in set. Elapsed: 0.003 sec. 

b64d9704419c :) 

7.3 使用场景

可以使用AggregatingMergeTree表来做增量数据统计聚合,包括物化视图的数据聚合。

注意 

  • AggregatingMergeTree表不能跟踪basic表,在执行inser select 之后查的数据无法进行聚合,只能inser select 之前的数据聚合
  • AggregatingMergeTree物化视图可以跟踪basic表,但是在视图创建前已经存在的数据不能被跟踪,只能跟踪聚合视图创建后新插入的数据

参考:

https://clickhouse.tech/docs/zh/engines/table-engines/mergetree-family/aggregatingmergetree/

https://www.cnblogs.com/jiashengmei/p/12048253.html

 

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值