详解clickhouse分区目录的合并过程

2022-04-25 09:35:48 浏览数 (1)

MergeTree的分区目录和传统意义上其他数据库有所不同。MergeTree的分区目录并不是在数据表被创建之后就存在的,而是在数据写入过程中被创建的。也就是说如果一张数据表没有任何数据,那么也不会有任何分区目录存在。MergeTree的分区目录伴随着每一批数据的写入(一次INSERT语句),MergeTree都会生成一批新的分区目录。即便不同批次写入的数据属于相同分区,也会生成不同的分区目录。也就是说,对于同一个分区而言,也会存在多个分区目录的情况。在之后的某个时刻(写入后的10~15分钟,也可以手动执行optimize查询语句),ClickHouse会通过后台任务再将属于相同分区的多个目录合并成一个新的目录。已经存在的旧分区目录并不会立即被删除,而是在之后的某个时刻通过后台任务被删除(默认8分钟)。

下面我们来看一个示例:

代码语言:javascript复制
## 表结构
CREATE TABLE mytest.test_mergetree
(
    `id` Int32 COMMENT 'id',
    `name` String COMMENT '名称',
    `age` Int32 COMMENT '年龄',
    `create_at` DateTime COMMENT '创建时间'
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(create_at)
PRIMARY KEY id
ORDER BY id
TTL create_at   toIntervalMonth(1)
SETTINGS index_granularity = 8192

#分三次进行insert操作:
insert into mytest.test_mergetree (id,name,age,create_at) values(1,'我的名次',34,'2022-03-17 23:40:54')

生成目录如下:

代码语言:javascript复制
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:42 202203_1_1_0
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:42 202203_2_2_0
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:42 202203_3_3_0
-rw-r----- 1 clickhouse clickhouse    1 Mar 17 23:39 format_version.txt

执行如下命令:

代码语言:javascript复制
optimize table mytest.test_mergetree

目录多了一个,具体如下:这里只有最后重新合并的目录202203_1_3_1是有效的。

代码语言:javascript复制
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:42 202203_1_1_0
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:51 202203_1_3_1
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:42 202203_2_2_0
drwxr-x--- 2 clickhouse clickhouse 4096 Mar 17 23:42 202203_3_3_0
-rw-r----- 1 clickhouse clickhouse    1 Mar 17 23:39 format_version.txt

下面我们来看下当前表下面active=1的目录:这里是目前还没被删除的情况。

代码语言:javascript复制
SELECT
    partition,
    path,
    active
FROM parts
WHERE table = 'test_mergetree'
FORMAT Vertical

Query id: 3efb78af-4b85-414b-b4bb-598c1aa7a745

Row 1:
──────
partition: 202203
path:      /var/lib/clickhouse/store/499/49983a25-98e6-45cc-bc4e-a0823e237565/202203_1_1_0/
active:    0

Row 2:
──────
partition: 202203
path:      /var/lib/clickhouse/store/499/49983a25-98e6-45cc-bc4e-a0823e237565/202203_1_3_1/
active:    1

Row 3:
──────
partition: 202203
path:      /var/lib/clickhouse/store/499/49983a25-98e6-45cc-bc4e-a0823e237565/202203_2_2_0/
active:    0

Row 4:
──────
partition: 202203
path:      /var/lib/clickhouse/store/499/49983a25-98e6-45cc-bc4e-a0823e237565/202203_3_3_0/
active:    0

当通过后台任务执行删除完成之后,则查询文件只有一个了。结果如下:

代码语言:javascript复制
SELECT
    partition,
    path,
    active
FROM parts
WHERE table = 'test_mergetree'
FORMAT Vertical

Query id: 54ae8515-1006-42af-ade1-28058293248c

Row 1:
──────
partition: 202203
path:      /var/lib/clickhouse/store/499/49983a25-98e6-45cc-bc4e-a0823e237565/202203_1_3_1/
active:    1

通过上面的例子我们总结一下,分区目录的名称由PartitionID、MinBlockNum、MaxBlockNum和Level组成,属于同一个分区的多个目录,在合并之后会生成一个全新的目录,目录中的索引和数据文件也会相应地进行合并。新目录名称的合并方式遵循以下规则:

  • MinBlockNum:取同一分区内所有目录中最小的MinBlockNum值。
  • MaxBlockNum:取同一分区内所有目录中最大的MaxBlockNum值。
  • Level:取同一分区内最大Level值并加1。

根据上面的例子:202203_1_3_1目录中MinBlockNum取的是202203_1_1_0的1,MaxBlockNum取的是202203_3_3_0的3,Level取的是同一分区内最大Level值并加1

下面我们来看下图,分区目录的创建,合并,删除的过程。

总结:

1:分区的目录命名主要是由PartitionID、MinBlockNum、MaxBlockNum和Level组成。

2:为什么会有合并目录的过程,其实主要是clickhouse是异步对数据合并并进行压缩,为了节省空间。

0 人点赞