【ClickHouse系列】MergeTree引擎介绍

MergeTree引擎介绍

Clickhouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(*MergeTree)中的其他引擎。

MergeTree 系列中的引擎目的在于将大量数据插入表中,数据迅速地一部分一部分写入表中,然后在后台通过某些规则进行数据合并。这种方法比插入期间连续重写存储中的数据效率更高。

特点

  • 数据存储按主键排序

  • 支持数据分区

  • 支持数据复制(ReplicatedMergeTree)

  • 支持数据采样

建表语句

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]
  • ENGINE:引擎名和参数, ENGINE = MergeTree(). MergeTree 引擎没有参数
  • PARTITION BY:分区键,要按月分区,可以使用表达式 toYYYYMM(date_column)
  • ORDER BY:排序键,例如: ORDER BY (CounterID, EventDate)
  • PRIMARY KEY:主键,默认情况下主键跟排序键(由 ORDER BY 子句指定)相同,大部分情况下不需要再专门指定一个 PRIMARY KEY 子句。
  • SAMPLE BY:用于抽样的表达式。如果要用抽样表达式,主键中必须包含这个表达式,例如SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))
  • SETTINGS:影响 MergeTree 性能的额外参数:
    • index_granularity:索引粒度。即索引中相邻『标记』间的数据行数。默认值,8192 。该列表中所有可用的参数可以从这里查看 MergeTreeSettings.h 。
    • index_granularity_bytes:索引粒度,以字节为单位,默认值: 10Mb。如果仅按数据行数限制索引粒度, 请设置为0(不建议)。
    • enable_mixed_granularity_parts:启用或禁用通过 index_granularity_bytes 控制索引粒度的大小。在19.11版本之前, 只有 index_granularity 配置能够用于限制索引粒度的大小。当从大表(数十或数百兆)中查询数据时候,index_granularity_bytes 配置能够提升ClickHouse的性能。如果你的表内数据量很大,可以开启这项配置用以提升SELECT 查询的性能。
    • use_minimalistic_part_header_in_zookeeper:数据片段头在 ZooKeeper 中的存储方式。如果设置了 use_minimalistic_part_header_in_zookeeper=1 ,ZooKeeper 会存储更少的数据。
    • min_merge_bytes_to_use_direct_io:使用直接 I/O 来操作磁盘的合并操作时要求的最小数据量。合并数据片段时,ClickHouse 会计算要被合并的所有数据的总存储空间。如果大小超过了 min_merge_bytes_to_use_direct_io 设置的字节数,则 ClickHouse 将使用直接 I/O 接口(O_DIRECT 选项)对磁盘读写。如果设置 min_merge_bytes_to_use_direct_io = 0 ,则会禁用直接 I/O。默认值:10 * 1024 * 1024 * 1024 字节。
    • merge_with_ttl_timeout:TTL合并频率的最小间隔时间。默认值: 86400 (1 天)。
    • write_final_mark:启用或禁用在数据片段尾部写入最终索引标记。默认值: 1(不建议更改)。
    • storage_policy:存储策略。

数据存储方式

主键索引

表数据是按照主键顺序存储的。如果主键表达式中有多个列,则会先按照第一个列排序,如果第一个列中值是相同的再按照第二个列,排序方式类似MySQL的order by column1,column2产生的的结果。

分区键

如果表设置了分区键,数据会根据分区键插入到不同的分区,否则会都插入到一个分区中。同分区中的parts才会进行merge操作。

每个数据逻辑上可以被看做一个颗粒,多个颗粒被存储在一个颗粒集中,颗粒集的大小就是由上述index_granularity参数设定的,主键索引就是由连续的颗粒集中的首行构成的,所以这个颗粒集就是ClickHouse在select数据时的最小集合。

例如:

  Whole data:[-------------------------------------------------------------------------]
  CounterID: [aaaaaaaaaaaaaaaaaabbbbcdeeeeeeeeeeeeefgggggggghhhhhhhhhiiiiiiiiikllllllll]
  Date:      [1111111222222233331233211111222222333211111112122222223111112223311122333]
  Marks:      |      |      |      |      |      |      |      |      |      |      |    
             a,1    a,2    a,3    b,3    e,2    e,3    g,1    h,2    i,1    i,3    l,3 
  Marks num:  0      1      2      3      4      5      6      7      8      9      10

注:采用稀疏索引会导致在查询数据时会多查询2*index_granularity个数据,但是ClickHouse每个列都分别存为一个文件,通过并行处理弥补了这一劣势。

在查询数据时,可以利用主键索引配合分区键作为条件,ClickHouse会现根据分区键缩小范围,再根据主键去查询数据。

局部单调索引

以时间索引来说,在一个月内的天都是单调递增有序的,但是在多个月中的天就不是有序的,如果在查询条件中只涉及到一个月内,ClickHouse会进行分析,进而会使用索引去查询数据,如果条件中没有限定到一个月内,则ClickHouse会扫描全部数据。

跳数索引

这些索引是由数据块按粒度分割后的每部分在指定表达式上汇总信息 granularity_value 组成(粒度大小用表引擎里 index_granularity 的指定)。

CREATE TABLE table_name
(
    u64 UInt64,
    i32 Int32,
    s String,
    ...
    INDEX a (u64 * i32, s) TYPE minmax GRANULARITY 3,
    INDEX b (u64 * length(s)) TYPE set(1000) GRANULARITY 4
) ENGINE = MergeTree()
...

并发访问

应对表的并发访问,我们使用多版本机制。换言之,当同时读和更新表时,数据从当前查询到的一组片段中读取。没有冗长的的锁。插入不会阻碍读取。

对表的读操作是自动并行的。

列和表的TTL

TTL可以设置值的生命周期,它既可以为整张表设置,也可以为每个列字段单独设置。如果TTL同时作用于表和字段,ClickHouse会使用先到期的那个。

列字段TTL

当列字段中的值过期时,ClickHouse会将它们替换成数据类型的默认值。如果分区内,某一列的所有值均已过期,则ClickHouse会从文件系统中删除这个分区目录下的列文件。

TTL子句不能被用于主键字段。例如:

CREATE TABLE example_table
(
    d DateTime,
    a Int TTL d + INTERVAL 1 MONTH,
    b Int TTL d + INTERVAL 1 MONTH,
    c String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d;

注:列字段如果过期部分被删掉。在查询时返回的是数据类型字符串,在处理数据时需注意,建议少用这种设置

表 TTL

当表内的数据过期时,ClickHouse会删除所有对应的行。例如:

CREATE TABLE example_table
(
    d DateTime,
    a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d + INTERVAL 1 MONTH;

数据删除

ClickHouse没有删除功能,数据删除大体有两种方式:TTL过期删除和手动删除partition。TTL过期删除是在merge数据块时进行的,如果在merge时执行查询有可能查到过期数据,此时可以提前执行OPTIMIZE来避免这种情况。手动删除就是直接删掉所有指定分区文件,数据直接被删掉了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章