【问题标题】:How to understand part and partition of ClickHouse?如何理解 ClickHouse 的部分和分区?
【发布时间】:2020-05-25 07:59:00
【问题描述】:

我看到 clickhouse 为每个分区键创建了多个目录。

Documentation says目录名格式为:分区名最小数据块数最大数据块数块级别。例如,目录名称为201901_1_11_1

我认为这意味着该目录是属于分区201901的一部分,具有从111的块并且在1 级。所以我们可以有另一部分,其目录类似于201901_12_21_1,这意味着这部分属于分区201901,有从1221的块> 并且在级别 1

所以我认为分区被分成不同的部分。 我说的对吗?

【问题讨论】:

  • Not - 分区不拆分为部分,分区是从部分中收集的。最初部分由 INSERT 生成(因此遵循insert rule 非常重要)并定期合并为几个大部分(理想情况下每个分区只有一个部分)。看这个解释:github.com/ClickHouse/ClickHouse/issues/…
  • @vladimir 感谢您的回复。根据您的回答,在一个零件目录中,我们可以有多个分区,每个分区在零件目录中都有自己的目录。而当我们读取数据时,我们需要检查零件中的每个分区范围来选择读取哪个。我理解的对吗?

标签: clickhouse


【解决方案1】:

Parts——存储行的表的片段。一个部分 = 一个带有列的文件夹。

分区是虚拟实体。他们没有物理表示。但是你可以说这些部分属于同一个分区。


Select 不关心分区。

Select 不知道分区键。

因为每个部分都有特殊文件 minmax_{PARTITIONING_KEY_COLUMN}.idx 这些文件包含这部分中这些列的最小值和最大值。 此外,这个 minmax_ 值存储在内存中的(c++ 向量)部件列表中。

create table X (A Int64, B Date, K Int64,C String) 
Engine=MergeTree partition by (A, toYYYYMM(B)) order by K;

insert into X values (1, today(), 1, '1');

cd /var/lib/clickhouse/data/default/X/1-202002_1_1_0/
ls -1 *.idx
minmax_A.idx   <-----
minmax_B.idx   <-----
primary.idx

SET send_logs_level = 'debug';
select * from X where A = 555;

(SelectExecutor): MinMax index condition: (column 0 in [555, 555])
(SelectExecutor): Selected 0 parts by date

SelectExecutor 检查内存中的零件列表并找到 0 个零件,因为 minmax_A.idx = (1,1) 并且此选择需要 (555, 555)。

CH 不存储分区键值。

例如 toYYYYMM(today()) = 202002 但是这个 202002 没有存储在零件或任何地方。

minmax_B.idx 商店 (18302, 18302) (2020-02-10 == select toInt16(today()))

【讨论】:

  • 我认为 minmax 索引是跳过索引之一。我看到你创建表时没有指定最小最大索引,MergeTree会默认创建最小最大索引?
  • @GOGO 你错了。这就是分区和分区修剪的工作原理。我发现了这一点,并使用 clickHouse 版本 1.1.54394,2018-07-12 为自己发出了通知,该版本在跳过索引发明前 2 年发布。
  • 谢谢。如您所说,一份属于一个分区?并且每个part的partition范围都记录在part目录名中?
  • @GOGO 分区编码在部件名称(文件夹名称)中。 1-202002_1_1_0 -- 1-202002 -- 分区(名称)。 1_1 - 块范围(1 - 只是一个序列号 - uniq 块标识符)。 0 -- 级别(0 插入 -- 从不合并)clickhouse.tech/docs/en/operations/table_engines/…
  • 使用旧(废弃)语法表创建的表有另一个部分命名,部分(文件夹)名称包含日期范围 20200215_20200215_1_1_0
【解决方案2】:

在我的例子中,我使用 groupArray() 和 arrayEnumerate() 在 Populate 中进行排名。我认为 Populate 可以使用分区上的新数据运行查询(在我的情况下:toStartOfDay(Date)),新插入数据的总和是正确的,但是 groupArray() 函数不能正常工作。

我认为这是因为当插入一个 Part 时,CH 将 groupArray() 并立即对每个 Part 进行排名,然后将 Parts 合并到一个 Partition 中,因此我不会得到 groupArray() 和 arrayEnumerate() 函数的最终结果。 总结,合并

[groupArray(part_1) + groupArray(part_2)] 不同于 groupArray(分区)

分区=part_1 + part_2

我尝试的解决方案是将新数据作为一个块大小插入,就像使用 groupArray() 将新数据减少到低于 max_insert_block_size=1048576 的行数一样。它做得正确,但很难将 1 天的新数据作为一个 Part 插入,因为在填充 1 天的数据(几乎 150Mn-200Mn 行)时会占用过多的内存进行查询。

但是您是否有另一种使用 groupArray() 填充新插入数据的解决方案,例如强制 CH 在每个分区上使用 POPULATE,而不是在将所有部分合并到一个分区后的每个部分?

【讨论】:

    猜你喜欢
    • 2019-01-17
    • 2019-11-22
    • 1970-01-01
    • 2021-05-07
    • 2019-07-28
    • 2021-06-26
    • 2020-05-31
    • 2016-06-04
    • 1970-01-01
    相关资源
    最近更新 更多