我是靠谱客的博主 精明篮球,最近开发中收集的这篇文章主要介绍clickhouse MergeTree序列表引擎1、MergeTree2、ReplacingMergeTree3、SummingMergeTree4、AggregatingMergeTree5、CollapsingMergeTree6、VersionedCollapsngMergeTree7、各种MergeTree之间的关系,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1、MergeTree

1.1数据TTL

1.1.1列级别TTL

-- 创建一张包含列级别TTL的表
create table test.ttl_table_v1 ( 
id String,  -- 主键字段不能被声明TTL表达式
create_time DateTime, 
-- 需要依托对某个DateTime或Date类型字段的INTERVAL操作,来表达TTL的过期时间
code String TTL create_time + INTERVAL 10 SECOND,  -- 当系统时间超过该TTL超时时间则字段会被清理并且设置为字段类型的默认值
type UInt8 TTL create_time + INTERVAL 10 SECOND 
)ENGINE = MergeTree() 
PARTITION BY toYYYYMM(create_time) 
ORDER BY id;
insert into table test.ttl_table_v1 values('A000', now(), 'C1', 1), 
('A000', now()+ INTERVAL 10 MINUTE, 'C1', 1);
select * from test.ttl_table_v1;
-- 执行强制触发TTL清理
optimize table test.ttl_table_v1 final;
-- 修改表的TTL字段或者新增TTL字段
alter table test.ttl_table_v1 modify column code string TTL create_time + INTERVAL 1 DAY

1.1.2表级别TTL

create table test.ttl_table_v2 ( 
id String, 
create_time DateTime, 
code String TTL create_time + INTERVAL 10 SECOND, 
type UInt8 
)ENGINE = MergeTree() 
PARTITION BY toYYYYMM(create_time) 
ORDER BY create_time 
-- 这里定义表级别的TTL,当出发TTL清除的时候,满足过期时间的数据行将会被删除
TTL create_time + INTERVAL 1 DAY;
-- 新增或者修改表级别的TTL
alter table test.ttl_table_v1 modify TTL create_time + INTERVAL 3 DAY

1.1.3TTL运行机制

当设置表级别的TTL后,在写入数据的时候,会以数据分区为单位,在每个分区的目录里面生成一个ttl.txt的文件

[root@localhost test]# tree ttl_table_v2/
ttl_table_v2/
├── 202103_1_1_0
│   ├── checksums.txt
│   ├── columns.txt
│   ├── count.txt
│   ├── data.bin
│   ├── data.mrk3
│   ├── default_compression_codec.txt
│   ├── minmax_create_time.idx
│   ├── partition.dat
│   ├── primary.idx
│   └── ttl.txt
├── detached
└── format_version.txt
ttl format version: 1
{"columns":[{"name":"code","min":0,"max":0},{"name":"type","min":0,"max":0}],"table":{"min":1615175460,"max":1615176099}}
"columns":[{"name":"code","min":0,"max":0}]是列级别ttl的描述信息。
"table":{"min":1615175460,"max":1615176099}是表界别的tt描述信息。
min,max分别保存了当前数据分区中,ttl指定日期字段的最小值、最大值分别于INTERVAL表达式计算后的时间戳。

处理逻辑:

1、MergeTree以分区目录为单位,通过ttl.txt文件记录过期时间,并将其作为后续的判断依据。

2、每当写入一批数据,都会基于INTERVAL表达式计算结果为整个分区生成ttl.txt文件。

3、只有在MergeTree合并分区时,才会触发删除TTL过期数据的逻辑。

4、在选择删除分区时,会使用贪婪算法,它的算法规则是尽可能多的找到会最早过期的,同事年纪有事最老的分区(合并次数最多,MaxBlockNum更大的)。

Tips:

1、TTL默认等待合并频率是由MergeTree的merge_with_ttl_timeout参数控制,默认是一天。如果这个值被设置过小会有性能问题。

2、除了自动出发合并,也可以手动合并

-- 触发一个分区合并
optimize table table_name
-- 触发所有的分区合并
optimize table table_name final

3、目前没有提供删除TTL声明的方法,但是提供了控制全局TTL(不能按找表级别)合并任务的启停方法:

system stop/start ttl merges

 

1.2多路径存储策略

默认策略所有的分区数据会自动保存到config.xml配置的path路径中去。

JBOD策略适合服务器挂载了多块磁盘,但没有做RAID的场景。JBOD(just a bunch of disks)是一种轮询策略,每执行一次INSERT或者MERGE,所产生的新分区会轮询你写入各个磁盘,如果单块磁盘发生故障,则会丢掉应用JBOD策略写入的这部分数据。

HOT/COLD策略适合服务器挂在了不同类型磁盘的场景(SSD/HDD)。将存储分期HOT和COLD两类区域。HOT区域使用SSD,COLD区域使用HDD。数据在写入MerGeTree之初,首先会在HOT区域创建分区目录用于保存数据,当分区数据大小累积到阈值时,数据会自行移动到COLD区域。而在每个区域的内部,也支持定义多块磁盘,所以在单个区域的写入过程中也能应用JBOD策略。

配置存储策略的在config.xml中时storage_configuration标签,下面还有disks(磁盘)和policy(策略)两个标签。

<storage_configuration>
<disks>
<!--自定义磁盘名字-->
<disk_name_a>
<!--定义磁盘的路径-->
<path>/clickhouse/data</path>
<!--定义磁盘的预留空间-->
<keep_free_space_bytes>4096</keep_free_space_bytes>
</disk_name_a>
</disks>
<policies>
<!--自定义策略名字-->
<policy_name_a>
<volumes>
<!--卷的自定义名称-->
<volume_name_a>
<!--关联的配置内的磁盘-->
<disk>disk_name_a</disk>
<disk>disk_name_b</disk>
<!--表示在这个卷的单个disk磁盘中,一个数据分区的最大存储阈值,如果当前分区的数据大小超过阈值,
则之后的分区会写入下一个disk磁盘-->
<max_data_part_size_part>4096</max_data_part_size_part>
</volume_name_a>
</volumes>
<!--如果当前卷的可用空间小于factor因子,并且定义了多个卷,则数据会自定向下一个卷移动-->
<move_factor>2.0</move_factor>
</policy_name_a>
</policies>
</storage_configuration>

1.2.1JBOD策略

<storage_configuration>
<disks>
<!--自定义磁盘名字-->
<disk_hot>
<!--定义磁盘的路径-->
<path>/clickhouse/data</path>
<!--定义磁盘的预留空间-->
<keep_free_space_bytes>4096</keep_free_space_bytes>
</disk_hot>
<disk_cold>
<!--定义磁盘的路径-->
<path>/clickhouse/data</path>
<!--定义磁盘的预留空间-->
<keep_free_space_bytes>4096</keep_free_space_bytes>
</disk_cold>
</disks>
<policies>
<!--自定义策略名字-->
<default_jbod>
<volumes>
<!--卷的自定义名称-->
<jbod>
<!--关联的配置内的磁盘-->
<disk>disk_hot</disk>
<disk>disk_cold</disk>
</jbod>
</volumes>
</default_jbod>
</policies>
</storage_configuration>

以上就配置好了JBOD存储策略了。在使用之前记得把两个存储目录的拥有者修改为clickhosue的用户,并且需要重启clickhouse-server服务。

执行以SQL可以查看配置的磁盘:

select 
name, 
path, 
formatReadableSize(free_space) as free, 
formatReadableSize(total_space) as total_space, 
formatReadableSize(keep_free_space) as keep_free_space 
from 
system.disks;

执行以下SQL查看配置的存储策略:

select * from system.storage_policies;

使用配置的策略:

-- 创建表
create table test.jbod_table(
id UInt64
)engine = MergeTree()
Order By id
-- 配置表的存储策略
Setting storage_policy = 'default_jbod'
-- 写入数据
insert into table jbod_table select rand() from numbers(10);
-- 查看分区系统表, 分区存储在哪个磁盘上
select name, disk_name from system.parts where table = 'test.jbod_table';

总结:多个磁盘组成了一个磁盘组,即volume卷。每当生成一个新的数据分区的时候,分区目录会按照volume卷重磁盘定义的顺序,依次轮询写入各个磁盘。

1.2.2HOT/COLD策略

<storage_configuration>
<disks>
<!--自定义磁盘名字-->
<disk_hot>
<!--定义磁盘的路径-->
<path>/clickhouse/data</path>
<!--定义磁盘的预留空间-->
<keep_free_space_bytes>4096</keep_free_space_bytes>
</disk_hot>
<disk_cold>
<!--定义磁盘的路径-->
<path>/clickhouse/data</path>
<!--定义磁盘的预留空间-->
<keep_free_space_bytes>4096</keep_free_space_bytes>
</disk_cold>
</disks>
<policies>
<!--自定义策略名字-->
<moving_from_hot_to_cold>
<volumes>
<!--卷的自定义名称-->
<hot>
<!--关联的配置内的磁盘-->
<disk>disk_hot</disk>
<!--表示在这个磁盘下如果一个分区数据大小超过1M,则需要被移动到紧邻的下一个磁盘卷-->
<max_data_part_size>1073741824</max_data_part_size>
</hot>
<cold>
<disk>disk_cold</disk>
</cold>
</volumes>
<!--如果当前卷的可用空间小于factor因子,并且定义了多个卷,则数据会自定向下一个卷移动-->
<move_factor>2.0</move_factor>
</moving_from_hot_to_cold>
</policies>
</storage_configuration>

使用配置的策略:

-- 创建表
create table test.hot_cold_table(
id UInt64
)engine = MergeTree()
Order By id
-- 配置表的存储策略
Setting storage_policy = 'moving_from_hot_to_cold'
-- 写入数据
insert into table hot_cold_table select rand() from numbers(10);
-- 查看分区系统表, 分区存储在哪个磁盘上
select name, disk_name from system.parts where table = 'test.hot_cold_table';

Tips:

1、如果一次性写入1MB,分区也会被写入COLD卷中

2、多个磁盘卷组成一个磁盘组volume组,每当生成一个新数据分区的时候,按照阈值大小(max_data_part_size),分区目录会按照volume组中磁盘卷定义的顺序,依次轮询写入各个卷下的磁盘。

3、MergeTree的存储册罗目前不能修改,但是分区目录却可以移动。

-- 将某个分区移动到当前存储策略中当前卷下的其他的disk磁盘:
alter table hot_cold_table move part "all_1_2_1" to disk "disk_hot1"
-- 将某个分区移动到当前存储策略中其他的volume卷
alter table hot_cold_table move part "all_1_2_1" to volume "cold"

 

2、ReplacingMergeTree

ReplacingMergeTree是为了去重而设计的,能够在分区合并的时候删除重复的数据。

使用时只需要把ENGINE = ReplacingMergeTree(ver),这里的ver是一个选填参数,会指定一个UInt*、Date或者DateTime类型的字段作为版本号,这个参数决定了数据去重时使用的算法。

-- 创建表
create table test.replace_table ( 
id String, 
create_time DateTime, 
code String 
)ENGINE = ReplacingMergeTree() 
PARTITION BY toYYYYMM(create_time) 
ORDER BY (id, code) 
primary key id;
-- 执行以下的命令2次及以上
insert into table test.replace_table values('A111', '2020-03-05 15:00:00', 'C1'),('A111', '2020-04-05 15:00:00', 'C1'),('A111', '2020-05-05 15:00:00', 'C1');
-- 然后手动清理表
optimize table test.replace_table final;
-- 然后查看表数据, 最后主键还是有重复的
select * from test.replace_table

Tips1:ReplacingMergeTree是以分区为单位删除重复数据的。只有在相同的数据分区重复的数据才可以删除,而不同的数据分区之间的重复数据依然不能被删除。

-- 创建表,这里加上版本号字段
create table test.replace_table ( 
id String, 
create_time DateTime, 
code String 
)ENGINE = ReplacingMergeTree(create_time) 
PARTITION BY toYYYYMM(create_time) 
ORDER BY id 
primary key id;
optimize table test.replace_table final;

Tips2:如果加上了版本号字段的话,则在删除重复数据的时候,会保留同一组数据内版本号列字段最大的哪一行。

总结:

(1)使用order by排序键作为判断数据重复的唯一键

(2)只有在合并分区的时候才会触发删除重复数据的逻辑

(3)以数据分区为单位删除重复数据。当分区合并时,同意分区内的重复数据会被删除;不同分区之间的数据不能被删除。

(4)在进行数据去重时,因为分区内的数据已经基于order by进行了排序,所以能够找到那些相邻的重复数据。

(5)数据去重的两种策略:

  • 如果没有设置ver版本号,则保留同一组重复数据中的最后一行。
  • 如果设置了ver版本号,则保留同一组重复数据中ver字段取值最大的那一行。

3、SummingMergeTree

SummingMergeTree的聚合是根据ORDER BY定义的排序键进行的。通常情况下只需要通过定义排序键就能定义了主键,但是如果同时定义了排序键和主键的话,则要求主键列字段必须是排序键的前缀。

当需要修改排序键的时候通过以下的命令:

alter table table_name modify order by (A, B)

注意:在修改排序键的时候,只能在原有的基础上减少字段,如果是新增排序字段的话,那只能是添加通过alter add column新增的字段。

SummingMergeTree使用方法:

ENGINE = SummingMergeTree((col1, col2, …))
Col1, col2为columns参数值,这是一个选填参数,用于设置除主键外的其他数值类型字段,以指定被SUM汇总的列字段。如果不填此参数,则会将所有除主键之外的数值类型进行SUM汇总。

create table summing_table ( 
id String, 
city String, 
v1 UInt32, 
v2 Float64, 
create_time Datetime 
)ENGINE = SummingMergeTree() 
PARTITION BY toYYYYMM(create_time) 
ORDER BY (id, city) 
PRIMARY KEY id;

当使用嵌套数据类型的时候:

create table summing_table_nested ( 
id String, 
-- 在使用嵌套数据类型的时候,默认情况下,会以嵌套类型中的第一个字段作为聚合条件Key
-- 如果要使用嵌套中的复合字段作为聚合Key, 则除第一个字段外,任何名称是以Key, Id或Type为后缀结尾的字段,都将和第一个字段一起组成复合Key
nestMap Nested( 
id UInt32, 
Key UInt32, 
val UInt64 
), 
create_time Datetime 
)ENGINE = SummingMergeTree() 
PARTITION BY toYYYYMM(create_time) 
ORDER BY id;

总结

  1. 用Order BY 排序键作为聚合数据的条件Key
  2. 只有在合并分区的时候才会触发汇总的逻辑
  3. 以数据分区为单位来聚合数据。当分区合并的时,同一数据分区内聚合Key相同的数据会被合并汇总,而不同分区的数据则不会被汇总。
  4. 如果在定义引擎的时候指定了columns汇总列(非主键的数值类型字段),则SUM汇总这些列字段,如果未指定,则聚合所有的非主键的数值类型字段。
  5. 在进行数据汇总的时,同一分区内,相同聚合Key的多行数据会合并成一行。其中,汇总字段会进行SUM计算;对于那些非汇总字段,则会使用第一行数据的取值。
  6. 支持嵌套类型结构,但列字段必须以Map后缀收尾。嵌套类型中默认以第一个字段作为聚合Key。除第一个字段外,任何名称是以Key, Id或Type为后缀结尾的字段,都将和第一个字段一起组成复合Key。

4、AggregatingMergeTree

使用时设置:ENGINE = AggregatingMergeTree() ;

在分区合并时,在每个数据分区内,会按照ORDER BY聚合。而使用何种聚合函数,以及针对那些列字段计算,则是通过定义AggregatingFunction数据类型实现的。

create table agg_table ( 
id String, 
city String, 
-- uniq 去重操作
code AggregateFunction(uniq, String), 
-- sum 求和
value AggregateFunction(sum, UInt32), 
create_time datetime 
) engine = AggregatingMergeTree() 
partition by toYYYYMM(create_time) 
order by (id, city) 
primary key id;

AggregateFunction是clickhouse提供的一种特殊的数据类型,能够以二进制形式存储中间状态结果。

对于AggregateFunction的列字段在写入的时候需要调用*State函数;在查询数据的时候,需要调用相应的*Merge函数,其中*表示定义时使用的聚合函数。

写入的时候需要调用uniq、sum对应的uniqState和sumState函数,并使用INSERT SELECT:

insert into table agg_table
select 'A000', 'wuhan', uniqState('code01'), sumState(toUInt32(100)), '2021-03-06 00:08:00'

查询的时候,需要调用uniqMerge, sumMerge函数:

select id, city, uniqMerge(code), sumMerge(value) from agg_table group by id, city;

AggregatingMergeTree与物化视图结合使用:

  • (1)首先会有一张使用MergeTree的数据明细表作为底表,存储全量的明细数据,并对外提供实时查询。
create table agg_table_basic ( 
id String, 
city String, 
code String, 
value UInt32 
)ENGINE = MergeTree() 
partition by city 
order by (id, city);
  • (2)在底表的基础上创建一张物化视图,数据写入的时候写入到底表中,数据会自动同步到物化视图,并按照AggragatingMergeTree引擎的规则处理。查询时查询的是物化视图AggragatingMergeTree。
create materialized view agg_view 
engine = AggregatingMergeTree() 
partition by city 
order by (id, city) 
as select 
id, 
city, 
uniqState(code) as code, 
sumState(value) as value 
from agg_table_basic 
group by id, city;
insert into table agg_table_basic values('A000', 'wuhan', 'code1', 100), 
('A000', 'wuhan', 'code2', 200), 
('A000', 'sichuan', 'code1', 150), 
('A000', 'beijing', 'code3', 1000);
select id, city, sumMerge(value), uniqMerge(code) from agg_view group by id, city;

总结:

  1. 用order by 排序键作为数据聚合的条件key
  2. 使用AggregationFunction字段类型定义聚合函数的类型以及聚合的字段。
  3. 只有在分区合并的时候才会触发聚合计算的逻辑。
  4. 以数据分区为单位来聚合数据,当分区合并时,同一数据分区内聚合Key相同的数据会被合并计算,而不同分区的数据则不会被计算。
  5. 在进行数据计算时,因为分区内的数据已经按照排序见排序,所以能找到相邻且拥有相同聚合key的数据。
  6. 在聚合数据时,同一分区内,相同聚合key的多行数据会合并成一行。对于非主键、非AggragateFunction类型字段,则会使用第一行数据的取值。
  7. AggragateFunction类型的字段使用二进制存储。对于AggregateFunction的列字段在写入的时候需要调用*State函数;在查询数据的时候,需要调用相应的*Merge函数,其中*表示定义时使用的聚合函数。
  8. AggragatingMergeTree通常作为物化视图的引擎,与普通MergeTree搭配使用。

5、CollapsingMergeTree

CollapsingMergeTree(折叠合并树)是通过以增代删的思路,支持行级别数据修改和删除的表引擎。

通过定义一个sign标记为字段,记录数据行的状态。如果sign标记为1,则表示这是一行有效的数据;如果sign为-1,这表示这行数据需要被删除。当CollapsingMergeTree分区合并到 时候,同一数据分区内,sign标记为1和-1的一组数据会被抵消删除。

 使用方法:ENGINE = CollapsingMergeTree(sign) 

create table collapse_table
(
id String,
code UInt32,
create_time DateTime,
-- sign 是一个Int8类型的标志位字段
sign Int8
)ENGINE = CollapsingMergeTree(sign)
partition by toYYYYMM(create_time)
order by id; // 以此处的排序键作为判断后续数据唯一性的依据

修改一行数据的操作:

-- 修改前的插入的数据
insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', 1)
-- 在修改之前需要删除该数据
insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', -1)
-- 修改数据的操作, 直接插入修改之后的数据
insert into table collapse_table values('A000', 200, '2021-04-22 00:00:00', 1)

删除数据的操作:

-- 插入数据
insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', 1)
-- 删除数据
insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', -1)

CollapsingMergeTree在折叠数据的时候,遵循以下规则:

  • 如果sign=1比sign=-1的数据多一行则保留最后一行sign=1的数据。
  • 如果sign=-1比sign=1的数据多一行则保留第一行sign=-1的数据。
  • 如果sign=-1和sign=1的数据行一样多,并且最后一行是sign=1,则保留第一行sign=-1和最后一行sign=1的数据。
  • 如果sign=1和sign=-1的数据行一样多,并且最后一行是sign=-1,则什么也不保留。
  • 其余情况Clickhouse会打印警告日志信息,但不会报错,在这种情形下,查询结果不可预知。

注意:

1.折叠数据并不是实时触发的,数据折叠只会在后台分区合并的时候发生,在分区合并之前,还是会看到旧的数据。

2.只有相同分区的数据才能被折叠

3.CollapsingMergeTree对写入数据的顺序有着严格的要求。比如先写入sign=1然后写入siign=-1的则可以被折叠,当顺序反过来则不能被折叠。

当写入的是单线程的话,则能较好控制写入顺序,当写入是多线程的时候则不能很好控制写入的顺序了。

6、VersionedCollapsngMergeTree

VersionedCollapsngMergeTree与CollapsingMergeTree作用完全相同,不同之处在于对数据的写入顺序没有要求,在同一个分区内,任意顺序的数据都能完成折叠要求。

在定义VersionedCollapsingMergeTree的时候,除了需要指定sign标记字段外,还需要指定一个Uint8类型的ver版本号字段。

create table ver_collapse_table (
id String,
code Int32,
create_time DateTime,
sign Int8,
ver Uint8
) ENGINE VersionedCollapsingMergeTree(sign, ver)
PARTITION BY toYYYYMM(create_time)
ORDER BY id;

通过自动将ver增加到ORDER BY的最后面,在每个数据分区内数据都会按照ORDER BY ${ORDER_KEY} ver DESC排序,所以写入的顺序无论是怎样的,在折叠的时候都能回到正确的顺序。

删除的时候:

insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', 1, 1)
-- 删除的时候sign=-1 版本号保持不变
insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', -1, 1)

更新的时候:

insert into table collapse_table values('A000', 100, '2021-04-22 00:00:00', -1, 1)
insert into table collapse_table values('A000', 102, '2021-04-22 00:00:00', 1, 1)
insert into table collapse_table values('A000', 103, '2021-04-22 00:00:00', 1, 2)

7、各种MergeTree之间的关系

1、继承关系


|-----ReplacingMergeTree
|
|
|
|-----SummingMergeTree
|
|
|
|-----AggragatingMergeTree
|
MergeTree-|
|
|-----CollapsingMergeTree
|
|
|
|-----VersionedCollapsingMergeTree
|
|
|
|-----GraphiteMergeTree

2、组合关系

【Replicated】   +  【Replacing, Summing, Aggregating, Collapsing, VersionedCollapsing, Graphite】 + 【MergeTree】

【Replacing, Summing, Aggregating, Collapsing, VersionedCollapsing, Graphite】 + 【MergeTree】可以组合成7种表引擎

【Replicated】   +  【Replacing, Summing, Aggregating, Collapsing, VersionedCollapsing, Graphite】 + 【MergeTree】可以组合成14种表引擎

 

最后

以上就是精明篮球为你收集整理的clickhouse MergeTree序列表引擎1、MergeTree2、ReplacingMergeTree3、SummingMergeTree4、AggregatingMergeTree5、CollapsingMergeTree6、VersionedCollapsngMergeTree7、各种MergeTree之间的关系的全部内容,希望文章能够帮你解决clickhouse MergeTree序列表引擎1、MergeTree2、ReplacingMergeTree3、SummingMergeTree4、AggregatingMergeTree5、CollapsingMergeTree6、VersionedCollapsngMergeTree7、各种MergeTree之间的关系所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部