Clickhouse MergeTree排序键建立后还能修改吗?

这个问题需要分情况讨论,首先有2个前提:

  1. MergeTree主键建立以后是不能修改的
  2. 主键必须和排序键一致或是排序键的前缀,即主键是A,排序键可以是A或(A,B),但不能是B

一、场景模拟

建立test表:

CREATE TABLE default.test
(
    `t_date` Date,
    `t_device_id` String,
    `app_name` String,
    `package_name` String,
    `launch_time` UInt32
)
ENGINE = MergeTree
PARTITION BY t_date
PRIMARY KEY t_date
ORDER BY t_date
SETTINGS index_granularity = 8192

在前面两个前提下,我们建立4种模拟场景:

        1. 主键和排序键一致,均为A,修改排序键为(A,B) -- 达咩

alter table test modify order by (t_date,t_device_id);

        2.主键和排序键一致,均为A,新增一列C,修改排序键为(A,C)--OK

alter table test add column country String, modify order by (t_date,country);

        3.主键是排序键的前缀,主键为A,排序键为(A,B,C),修改排序键为(A,B) --OK

--先建立排序键为(A,B,C)
alter table test add column version String, modify order by (t_date,country,version);
--删除C,只留下(A,B)
alter table test modify order by (t_date,country)

        4.主键是排序键的前缀,主键为A,排序键为(A,B,C),修改排序键为(A,C) -- 达咩

--重新构建排序键为(A,B,C)
alter table test drop column version;
alter table test add column version String, modify order by (t_date,country,version);
--删除中间的B,修改排序键为(A,C)
alter table test  modify order by (t_date,version);

        结论:MergeTree排序键的修改只能是在原有的基础上添加新增的字段,或者在原有的基础上删除后面的字段。为什么呢?这就需要理解MergeTree索引原理。

二、MergeTree索引原理

        MergeTree一级索引由主键定义(前文说过主键和排序键的关系)采用稀疏索引,存储在primary.idx文件中。下图来自clickhouse官网中文版,根据下图我们可以看出,MergeTree会根据排序键(CounterID, Date)对数据进行排序,每隔index_granularity(图中为7,默认是8192)把数据分割成多个小区间,并取出区间的第一个索引标记存入primary.idx文件,与之对齐会建立标记号存入.mrk文件。

         MergeTree二级索引由INDEX...GRANULARITY 定义

INDEX index_name expr TYPE type(...) GRANULARITY granularity_value

        二级索引采用跳数索引,跳数索引是指数据片段按照粒度(建表时指定的index_granularity)分割成小块后,将上述SQL的granularity_value数量的小块组合成一个大的块,对这些大块写入索引信息,这样有助于使用where筛选时跳过大量不必要的数据,减少SELECT需要读取的数据量。

        

        在Clickhouse中,分区、索引、标记和压缩数据,就好比是MergeTree给出的一套组合拳,共同完成大量数据的高效写入和快速查询。

数据写入:

        数据写入的第一步是生成分区目录,伴随着每一批数据的写入,都会生成一个新的分区目录。在后续的某一时刻,属于相同分区的目录会依照规则合并到一起;接着,按照index_granularity索引粒度,会分别生成primary.idx一级索引(如果声明了二级索引,还会创建二级索引文件)、每一个列字段的.mrk数据标记和.bin压缩数据文件。下图所示是一张MergeTre表在写入数据时,它的分区目录、索引、标记和压缩数据的生成过程。

        从分区目录201403_1_34_3能够得知,该分区数据共分34批写入,期间发生过3次合并。在数据写入的过程中,依据index_granularity的粒度,依次为每个区间的数据生成索引、标记和压缩数据块。其中,索引和标记区间是对齐的,而标记与压缩块则根据区间数据大小的不同,会生成多对一、一对一和一对多三种关系。
 

数据查询:

        数据查询的本质,可以看作一个不断减小数据范围的过程。在最理想的情况下,MergeTree首先可以依次借助分区索引、一级索引和二级索引,将数据扫描范围缩至最小。然后再借助数据标记,将需要解压与计算的数据范围缩至最小。下图所示为例,它示意了在最优的情况下,经过层层过滤,最终获取最小范围数据的过程。
 

         

三、总结(十万个为什么)

1. 为什么MergeTree主键建立以后不能修改?

        因为主键索引的建立依赖于排序键,主键索引按照排序顺序建立稀疏索引,如果修改主键,那么意味着需要对所有数据进行重新排序,这对于大数据来说是非常可怕的。

2. 为什么主键必须是排序键或其前缀?

        保证即便是主键和排序键不同的情况下,因为主键是排序键的前缀,无论如何不会出现索引和数据顺序混乱的情况。

3. 为什么不能添加已存在的列到排序键中?

        跟问题1一样,还是需要对已有数据重新排序的问题,消耗大量资源。

4. 为什么可以添加新增的列到排序键中?

        因为新增的列还没有数据,不需要对原有数据的顺序进行重排,只需要等数据插入时,将其插入到适当位置即可。

5. 模拟场景2中改一下,主键和排序键一致,均为A,新增一列C,修改排序键为(C,A)可以吗?

        当然不可,总之只要是需要对原有数据进行重排就一定不行!

6. 可以对排序键的记录进行update操作吗?

        不行的哦~

四、参考

        Clickhouse官网:MergeTree | ClickHouse Documentation

        《Clickhouse原理解析与应用实践》--朱凯

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值