MergeTree的分区目录和传统意义上其他数据库有所不同。MergeTree的分区目录并不是在数据表被创建之后就存在的,而是在数据写入过程中被创建的。也就是说如果一张数据表没有任何数据,那么也不会有任何分区目录存在。MergeTree的分区目录伴随着每一批数据的写入(一次INSERT语句),MergeTree都会生成一批新的分区目录。即便不同批次写入的数据属于相同分区,也会生成不同的分区目录。也就是说,对于同一个分区而言,也会存在多个分区目录的情况。在之后的某个时刻(写入后的10~15分钟,也可以手动执行optimize查询语句),ClickHouse会通过后台任务再将属于相同分区的多个目录合并成一个新的目录。已经存在的旧分区目录并不会立即被删除,而是在之后的某个时刻通过后台任务被删除(默认8分钟)。
下面我们来看一个示例:
## 表结构
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')
生成目录如下:
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
执行如下命令:
optimize table mytest.test_mergetree
目录多了一个,具体如下:这里只有最后重新合并的目录202203_1_3_1是有效的。
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的目录:这里是目前还没被删除的情况。
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
当通过后台任务执行删除完成之后,则查询文件只有一个了。结果如下:
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组成,属于同一个分区的多个目录,在合并之后会生成一个全新的目录,目录中的索引和数据文件也会相应地进行合并。新目录名称的合并方式遵循以下规则:
根据上面的例子: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是异步对数据合并并进行压缩,为了节省空间。