客快物流大数据项目(九十五):ClickHouse的CollapsingMergeTree深入了解
ClickHouse的CollapsingMergeTree深入了解
在ClickHouse中不支持对数据update和delete操作(不能使用标准的更新和删除语法操作CK),但在增量计算场景下,状态更新是一个常见的现象,此时update操作似乎更符合这种需求。
ClickHouse提供了一个CollapsingMergeTree表引擎,它继承于MergeTree引擎,是通过一种变通的方式来实现状态的更新。
CollapsingMergeTree表引擎需要的建表语句与MergeTree引擎基本一致,惟一的区别是需要指定Sign列(必须是Int8类型)。这个Sign列有1和-1两个值,1表示为状态行,当需要新增一个状态时,需要将insert语句中的Sign列值设为1;-1表示为取消行,当需要删除一个状态时,需要将insert语句中的Sign列值设为-1。
这其实是插入了两行除Sign列值不同,但其他列值均相同的数据。因为有了Sign列的存在,当触发后台合并时,会找到存在状态行与取消行对应的数据,然后进行折叠操作,也就是同时删除了这两行数据。
状态行与取消行不折叠有两种情况。
- 第一种是合并机制,由于合并在后台发生,且具体的执行时机不可预测,所以可能会存在状态行与取消行还没有被折叠的情况,这时会出现数据冗余;
- 第二种是当乱序插入时(CollapsingMergeTree仅允许严格连续插入),ClickHouse不能保证相同主键的行数据落在同一个节点上,但不同节点上的数据是无法折叠的。为了得到正确的查询结果,需要将count(col)、sum(col)改写成sum (Sign)、sum(col * Sign)。
如果在业务系统中使用ClickHouse的CollapsingMergeTree引擎表,当状态行已经存在,要插入取消行来删除数据的时候,必须存储一份状态行数据来执行insert语句删除。这种情况下,就有些麻烦,因为同一个业务数据的状态需要我们记录上一次原始态数据,和当前最新态的数据,才能完成原始态数据删除,最新态数据存储到ClickHouse中。
一、创建CollapsingMergeTree引擎表的语法
语法结构
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)参数说明
Sign是列名称,必须是Int8类型,用来标志Sign列。Sign列值为1是状态行,为-1是取消行。
二、创建CollapsingMergeTree引擎的表
create table tbl_test_collapsingmergetree_day_mall_sale (
mallId UInt64,
mallName String,
totalAmount Decimal(32,2),
cdt Date,
sign Int8
) engine=CollapsingMergeTree(sign) partition by toYYYYMMDD(cdt) order by mallId;
三、插入数据到CollapsingMergeTree引擎的表
第一次插入2条sign=1的数据
注意:当一行数据的sign列=1时,是标记该行数据属于状态行。也就是说,我们插入了两条状态行数据。
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(1,'西单大悦城',17649135.64,'2019-12-24',1);
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(2,'朝阳大悦城',16341742.99,'2019-12-24',1);
查询第一次插入的数据
select * from tbl_test_collapsingmergetree_day_mall_sale;
第二次插入2条sign=-1的数据
注意:当一行数据的sign列=-1时,是标记该行数据属于取消行(取消行有一个要求:除了sign字段值不同,其他字段值必须是相同的。这样一来,就有点麻烦,因为我们在状态发生变化时,还需要保存着未发生状态变化的数据。这个场景类似于修改数据,但由于ClickHouse本身的特性不支持update,所以其提供了一种变通的方式,即通过CollapsingMergeTree引擎来支持这个场景)。取消行指的是当这一行数据有了新的状态变化,需要先取消原来存储的数据,使ClickHouse合并时来删除这些sign由1变成-1的数据,虽然合并发生时机不确定,但如果触发了合并操作就一定会被删除。这样一来,我们将有新状态变化的数据再次插入到表,就仍然是2条数据。
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(1,'西单大悦城',17649135.64,'2019-12-24',-1);
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(2,'朝阳大悦城',16341742.99,'2019-12-24',-1);
对表执行强制合并
optimize table tbl_test_collapsingmergetree_day_mall_sale final;
然后发现查询数据时,表中已经没有了数据。这表示当触发合并操作时,会合并状态行与取消行同时存在的数据。
第三次插入3条数据
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(1,'西单大悦城',17649135.64,'2019-12-24',1);
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(2,'朝阳大悦城',16341742.99,'2019-12-24',1);
insert into tbl_test_collapsingmergetree_day_mall_sale(mallId,mallName,totalAmount,cdt,sign) values(1,'西单大悦城',17649135.64,'2019-12-24',-1);
select * from tbl_test_collapsingmergetree_day_mall_sale;
- 点赞
- 收藏
- 关注作者
评论(0)