【ClickHouse系列】ClickHouse 轻量级删除原理

轻量级删除

旧的删除原理

ClickHouse 的删除是通过 mutation 来实现的,比如我们想删除某些记录:

ALTER TABLE test DELETE WHERE id < 100;

会在表 test 的数据目录中产生 mutation_{block_number}.txt 文件,内容如下:

format version: 1
create time: 2022-12-24 22:10:44
commands: DELETE WHERE id < 100

每个 part 的数据会在 执行完 mutation 后被删除,但是执行 mutation 会将 part 中的所有数据都读进内存,而后执行数据删除,再将处理后的数据再持久化到文件系统当中,这个过程是重量级的,速度会非常慢。

轻量级删除原理

ClickHouse 目前实现了轻量级删除,即添加了一个虚拟列 _row_exists 来标识该行数据是否被删除,_row_exists 有两种取值:0(已被删除)和1(未被删除)。这样将上述的 mutation 过程变为了更新 _row_exists 虚拟列的逻辑,因为 ClickHouse 在做列变更时只是处理被影响的列,其余列文件是通过 hardlink 的方式链接过去,当列很多时,会省去很多 IO 操作。

当然,_row_exists 也是会持久化的,因为不能因为重启或其他原因丢失了数据操作,所以同样会有 _row_exists.bin_row_exists.mrk 文件生成。但是这列所产生的文件并不是真正有用的数据,所以在后续异步执行 part merge 的时候会将标记删除的记录做真正的删除,_row_exists 列也就不再有存在的意义,也会随之被删除。

示例

创建一个 MergeTree 表

CREATE TABLE test
(
    `id` UInt64,
    `value` String
)
ENGINE = MergeTree
ORDER BY id
SETTINGS
    vertical_merge_algorithm_min_rows_to_activate = 1,
    vertical_merge_algorithm_min_columns_to_activate = 1,
    min_rows_for_wide_part = 1,
    min_bytes_for_wide_part = 1;

其中,vertical_merge_algorithm_min_rows_to_activatevertical_merge_algorithm_min_columns_to_activate 设置为1是为了让 MergeTree 使用 Vertical 算法进行 merge(ClickHouse 还有一种是 Horizontal 算法,具体区别可以参考 两种Merge算法(Horizontal和Vertical)的使用场景),min_rows_for_wide_part 和 min_bytes_for_wide_part设置为1是为了让 MergeTree 的 part 使用 Wide 模式(即每列都是独立文件)。

写入数据

INSERT INTO test SELECT number AS id, toString(number) AS value FROM numbers(10);

开启轻量级删除配置

SET allow_experimental_lightweight_delete = 1;

目前轻量级删除功能还是实验性功能,需要将上述配置参数设置为1才生效。

删除部分数据

DELETE FROM lwd_test WHERE (id % 3) = 0;

轻量级删除需使用 DELETE 子句,不再使用 ALTER TABLE DELETE 子句。

执行过后,可以发现 test 数据目录多了 mutation_2.txt 文件,内容为:

format version: 1
create time: 2022-12-24 22:44:43
commands: UPDATE _row_exists = 0 WHERE (id % 3) = 0

可见 DELETE 操作被转变为 UPDATE 操作。

在观察下 part 目录,文件列表为:

-rw-r-----  1 ck  ck    36B 12 24 22:44 _row_exists.bin
-rw-r-----  1 ck  ck    48B 12 24 22:44 _row_exists.mrk2
-rw-r-----  1 ck  ck   328B 12 24 22:44 checksums.txt
-rw-r-----  1 ck  ck    84B 12 24 22:44 columns.txt
-rw-r-----  1 ck  ck     2B 12 24 22:42 count.txt
-rw-r-----  1 ck  ck    10B 12 24 22:44 default_compression_codec.txt
-rw-r-----  1 ck  ck    70B 12 24 22:42 id.bin
-rw-r-----  1 ck  ck    48B 12 24 22:42 id.mrk2
-rw-r-----  1 ck  ck    16B 12 24 22:42 primary.idx
-rw-r-----  1 ck  ck    47B 12 24 22:42 value.bin
-rw-r-----  1 ck  ck    48B 12 24 22:42 value.mrk2

可见多了 _row_exists.bin_row_exists.mrk2 文件,说明标记删除被持久化了。

执行强制 merge

OPTIMIZE TABLE test FINAL

执行 OPTIMIZE 后,每个 partition 的 part 会被合并为一个 part,再看新生成的 part 的目录会发现已经不存在 _row_exists 相关的文件了。


欢迎添加WX:xiedeyantu,讨论技术问题。

猜你喜欢

转载自blog.csdn.net/weixin_39992480/article/details/128462618