ClickHouse入门:表引擎-SummingMergeTree

x33g5p2x  于2021-12-25 转载在 其他  
字(3.9k)|赞(0)|评价(0)|浏览(562)

前言
插件及服务器版本
服务器:ubuntu 16.04
ClickHouse:20.12.5

简介

SummingMergeTree表引擎主要用于只关心聚合后的数据,而不关心明细数据的场景,它能够在合并分区的时候按照预先定义的条件聚合汇总数据,将同一分组下的多行数据汇总到一行,这样即减少了数据行,又降低了后续汇总查询的开销,该引擎优势:

  • 减少额外的存储开销:终端用户只关心汇总结果,不会去查询明细数据,所以保存明细数据是不必要的
  • 减少额外的查询开销:虽然MergeTree引擎性能强大,但是每次查询都进行明细数据的聚合,对性能消耗更大

聚合规则及聚合依据说明

SummingMergeTree表引擎依据ORDER BY指定的字段进行聚合,PRIMARY KEY指定主键,但是ORDER BY可以指代主键,一般只声明ORDER BY即可。
如果需要同时定义ORDER BY与PRIMARY KEY,这种情况多用于聚合条件有变动时使用,例如:
假设有一张表有col1,col2,col3,col4四个字段,我们需要按照col1,col2进行聚合,则ORDERY BY声明如下:

ORDER BY  (col1,col2)

这样声明的话,该表的主键即为col1,col2,但是该表主要的过滤字段为col1,应该只使用col1作为主键,所以我们可以用一种更加优雅的定义形式:

ORDER BY  (col1,col2)
PRIMARY KEY col1

备注: 这里需要注意,PRIMARY KEY必须为ORDER BY的前缀,这种约定保障了即使在ORDER BY与PRIMARY KEY不同的时候,主键仍然是排序键的前缀,不会出现索引与数据顺序混乱的问题。

如果需要修改聚合字段组合,将先前的聚合依据增加字段或减少字段,可以直接对表进行ALTER操作,如下:

ALTER TABLE test_summing MODIFY ORDER BY (col1,col2,col3);

备注: 在修改ORDER BY时,会有一些限制,只能在现有的基础上减少字段,如果是新增排序字段,则只能通过ALTER ADD COLUMN新增字段,但是ALTER是一种元数据的操作,修改成本低

测试使用SummingMergeTree

SummingMergeTree表引擎声明方式如下
EGINE = SummingMergeTree((col1,col2,...))

col1,col2声明sum汇总的字段,如果不指定,默认聚合所有非主键外的数值字段。

普通数值类型字段聚合

示例如下:

create table test_summing (
shop_code String,
product_code String,
in_count Int,
out_count Int,
write_date DateTime
) ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(write_date)
ORDER BY (shop_code,product_code)
PRIMARY KEY shop_code;

插入测试数据:

insert into test_summing values ('1','短袖',100,100,'2020-12-17 21:18:00');

insert into test_summing values ('1','短袖',100,200,'2020-12-17 21:19:00');

insert into test_summing values ('1','短袖',100,100,'2020-12-17 21:20:00');

insert into test_summing values ('2','外套',100,100,'2020-12-17 21:18:00');

insert into test_summing values ('2','外套',100,100,'2020-12-17 21:19:00');

这里可以看到,依照shop_code,produce_code,对in_count,out_count进行了自动聚合,这里跟ReplacingMergeTree引擎一样,聚合只会发生在同分区内,不同分区的数据不会发生聚合,如下:

嵌套类型字段聚合

SummingMergeTree也支持嵌套类型的字段,在使用嵌套类型的字段时,需要被sum汇总的字段名必须以Map后缀结尾,嵌套Map类型聚合如下:

create table test_summing_map1 (
shop_code String,
product_code String,
in_count Int,
out_count Int,
nestMap Nested(
id Int,
key Int,
val Int
),
write_date DateTime
) ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(write_date)
ORDER BY (shop_code,product_code)
PRIMARY KEY shop_code;

insert into test_summing_map1 values ('1','短袖',100,100,[1],[2],[3],'2020-12-17 21:18:00');
insert into test_summing_map1 values ('1','短袖',100,200,[2],[2],[4],'2020-12-17 21:19:00');

触发聚合后,结果如下:

嵌套类型字段指定复合Key

在使用嵌套类型时,也支持使用复合Key作为数据聚合的条件,在嵌套类型的字段内,以Key 、Id、Type为后缀结尾的字段,都将和ORDER BEY指定的聚合字段组合成一个复合的key,进行聚合,例如:

nestMap Nested(
id Int,
Key Int,//首字母大写的Key
val Int
)

示例:

create table test_summing_map2 (
shop_code String,
product_code String,
in_count Int,
out_count Int,
nestMap Nested(
id Int,
Key Int,
val Int
),
write_date DateTime
) ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(write_date)
ORDER BY (shop_code,product_code)
PRIMARY KEY shop_code;

insert into test_summing_map2 values ('1','短袖',100,100,[1],[2],[3],'2020-12-17 21:18:00');

insert into test_summing_map2 values ('1','短袖',100,100,[1],[2],[3],'2020-12-17 21:18:00');

insert into test_summing_map2 values ('1','短袖',100,200,[2],[3],[4],'2020-12-17 21:19:00');

查看聚合结果:

这里可以看到:新的聚合结果,根据嵌套字段的Key和ORDER BY的字段进行了聚合,nestMap.val进行了sum

非数值类型数据或非聚合字段处理方式

SummingMergeTree聚合非数值类型数据时,或者是处理非聚合字段时,只会取相同key分区的第一条记录,例如:

create table test_summing_map (
shop_code String,
product_code String,
in_count Int,
out_count Int,
nestMap Nested(
id String,
Key String,
val String
),
write_date DateTime
) ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(write_date)
ORDER BY (shop_code,product_code)
PRIMARY KEY shop_code;

插入测试数据:

insert into test_summing_map values ('1','短袖',100,100,['1'],['Tracy'],['ZHENGZHOU'],'2020-12-17 21:18:00');
insert into test_summing_map values ('1','短袖',100,200,['2'],['Monica'],['QITAIHE'],'2020-12-17 21:19:00');
insert into test_summing_map values ('1','短袖',100,100,['3'],['Nesta'],['SHANGHAI'],'2020-12-17 21:20:00');

执行optimize强制触发聚合:

optimize table test_summing_map final;

总结

  • SummingMergeTree使用ORDER BY排序键作为聚合数据的依据
  • 只有在合并分区时才会触发汇总逻辑
  • 聚合只会发生在同分区内,不同分区的数据不会发生聚合
  • 如果SummingMergeTree((col1,col2,…))指定了字段,只会聚合指定字段,如果没有指定,会对所有非ORDER BY字段以外的非数值字段进行聚合
  • 汇总会对聚合的数值类型字段进行sum,对非聚合类型字段或者是非数值类型字段会取相同key分区的第一条
  • 支持嵌套结构,但列字段名必须以Map为后缀结尾,任何名称以Key 、Id、Type为后缀结尾的字段,都将和ORDER BEY指定的聚合字段组合成一个复合的key,进行聚合

相关文章