ClickHouse 表引擎介绍

表引擎

表引擎(即表的类型)决定了:

  • 数据的存储方式和位置,写到哪里以及从哪里读取数据
  • 支持哪些查询以及如何支持。
  • 并发数据访问。
  • 索引的使用(如果存在)。
  • 是否可以执行多线程请求。
  • 数据复制参数。

ClickHouse包含4大类表引擎类型: 合并树家族(MergeTree)、日志引擎系列(Log)、集成引擎(Integration)、用于其他特定功能的引擎(Special)

MergeTree表引擎系列

ReplacingMergeTree:在后台数据合并期间,对具有相同排序键的数据进行去重操作。

SummingMergeTree:当合并数据时,会把具有相同主键的记录合并为一条记录。根据聚合字段设置,该字段的值为聚合后的汇总值,非聚合字段使用第一条记录的值,聚合字段类型必须为数值类型。

AggregatingMergeTree:在同一数据分区下,可以将具有相同主键的数据进行聚合。

CollapsingMergeTree:在同一数据分区下,对具有相同主键的数据进行折叠合并。

VersionedCollapsingMergeTree

基于CollapsingMergeTree引擎,增添了数据版本信息字段配置选项。在数据依据ORDER BY设置对数据进行排序的基础上,如果数据的版本信息列不在排序字段中,那么版本信息会被隐式的作为ORDER BY的最后一列从而影响数据排序。

GraphiteMergeTree:用来存储时序数据库Graphites的数据。

MergeTree是该系列引擎中最核心的引擎,其他引擎均以MergeTree为基础,并在数据合并过程中实现了不同的特性,从而构成了MergeTree表引擎家族。

MergeTree表引擎

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

MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。

主要特点:

  • 存储的数据按主键排序。

这使得您能够创建一个小型的稀疏索引来加快数据检索。

  • 如果指定了 分区键 的话,可以使用分区。

在相同数据集和相同结果集的情况下 ClickHouse 中某些带分区的操作会比普通操作更快。查询中指定了分区键时 ClickHouse 会自动截取分区数据。这也有效增加了查询性能。

  • 支持数据副本。

ReplicatedMergeTree 系列的表提供了数据副本功能。更多信息,请参阅 数据副本 一节。

  • 支持数据采样。

创建表

建表DDL语法如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]

主要参数说明:

必选参数:

  • ENGINE:引擎名字,MergeTree引擎无参数。

  • ORDER BY:排序键,可以由一列或多列组成,决定了数据以何种方式进行排序,例如ORDER BY(CounterID, EventDate)。 如果没有显示指定PRIMARY KEY,那么将使用ORDER BY作为PRIMARY KEY。通常只指定ORDER BY即可。

可选参数:

  • PARTITION BY:分区键,指明表中的数据以何种规则进行分区。分区是在一个表中通过指定的规则划分而成的逻辑数据集。分区可以按任意标准进行,如按月、按日或按事件类型。为了减少需要操作的数据,每个分区都是分开存储的。

大多数情况下,不需要分使用区键。即使需要使用,也不需要使用比月更细粒度的分区键。分区不会加快查询(这与 ORDER BY 表达式不同)。永远也别使用过细粒度的分区键。不要使用客户端指定分区标识符或分区字段名称来对数据进行分区(而是将分区字段标识或名称作为 ORDER BY 表达式的第一列来指定分区)。

要按月分区,可以使用表达式 toYYYYMM(date_column) ,这里的 date_column 是一个 Date 类型的列。分区名的格式会是 “YYYYMM” 。

  • PRIMARY KEY:主键,设置后会按照主键生成一级索引(primary.idx),数据会依据索引的设置进行排序,从而加速查询性能。默认情况下,PRIMARY KEY与ORDER BY设置相同,所以通常情况下直接使用ORDER BY设置来替代主键设置。

  • SAMPLE BY:数据采样设置,如果显示配置了该选项,那么主键配置中也应该包括此配置。例如 ORDER BY CounterID / EventDate / intHash32(UserID)、SAMPLE BY intHash32(UserID)。

  • TTL:数据存活时间,可以为某一字段列或者一整张表设置TTL,设置中必须包含Date或DateTime字段类型。如果设置在列上,那么会删除字段中过期的数据。如果设置的是表级的TTL,那么会删除表中过期的数据。如果设置了两种类型,那么按先到期的为准。例如,TTL createtime + INTERVAL 1 DAY,即一天后过期。使用场景包括定期删除数据,或者定期将数据进行归档。

  • index_granularity:索引间隔粒度。MergeTree索引为稀疏索引,每index_granularity个数据产生一条索引。index_granularity默认设置为8092。

  • enable_mixed_granularity_parts:是否启动index_granularity_bytes来控制索引粒度大小。

  • index_granularity_bytes:索引粒度,以字节为单位,默认10Mb。

  • merge_max_block_size:数据块合并最大记录个数,默认8192。

  • merge_with_ttl_timeout:合并频率最小时间间隔,默认1天。

创建分区表后,可以使用如下命令查看表分区相关信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 SELECT 
 database, 
 table, 
 partition, 
 partition_id, 
 name, 
 active, 
 path 
 FROM system.parts 
 WHERE table = '<table_name>' 
  • partitionid: 分区ID
  • path: 分区目录路径

数据分区ID生成规则

数据分区规则由分区ID决定,分区ID由PARTITION BY分区键决定。根据分区键字段类型,ID生成规则可分为:

  • 未定义分区键

没有定义PARTITION BY,默认生成一个目录名为all的数据分区,所有数据均存放在all目录下。

  • 整型分区键

分区键为整型,那么直接用该整型值的字符串形式做为分区ID。

  • 日期类分区键

分区键为日期类型,或者可以转化成日期类型。

  • 其他类型分区键

String、Float类型等,通过128位的Hash算法取其Hash值作为分区ID。

数据分区目录命名规则

目录命名规则如下:

1
PartitionId_MinBlockNum_MaxBlockNum_Level
  • PartitionId

分区id。

  • MinBlockNum

最小分区块编号,自增类型,从1开始向上递增。每产生一个新的目录分区就向上递增一个数字。

  • MaxBlockNum

最大分区块编号,新创建的分区MinBlockNum等于MaxBlockNum的编号。

  • Level

合并的层级,被合并的次数。合并次数越多,层级值越大。

参考