clickhouse之表引擎

clickhouse同mysql一样,有着属于自己的很多引擎。

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

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

对于ck来说,目前位置包含了以下部分引擎:

1.集成外部系统的表引擎,支持方式有kafka,JDBC,ODBC,HDFS等
2.合并树家族(最为常用且重要)
3.日志家族
4.一些特别的表引擎,如字典,视图,集合,合并等。

clickhouse之表引擎_第1张图片

下面就上述的ck引擎做下简单的介绍

一 .TinyLog(很少使用)
最简单的表引擎,用于将数据存储在磁盘上。每列都存储在单独的压缩文件中。写入时,数据将附加到文件末尾。

并发数据访问不受任何限制:

  • 如果同时从表中读取并在不同的查询中写入,则读取操作将抛出异常
  • 如果同时写入多个查询中的表,则数据将被破坏。

这种表引擎的典型用法是 write-once:首先只写入一次数据,然后根据需要多次读取。查询在单个流中执行。换句话说,此引擎适用于相对较小的表(建议最多1,000,000行)。如果有许多小表,则使用此表引擎是适合的,因为它比需要打开的文件更少。当拥有大量小表时,可能会导致性能低下。并且它是不支持索引的

二.MergeTree
ClickHouse中最强大的表引擎当属MergeTree(合并树)引擎及该系列(*MergeTree)中的其他引擎,支持索引和分区,地位可以相当于innodb之于Mysql。 而且基于MergeTree,还衍生除了ReplacingMergeTree,SummingMergeTree等很有特色的引擎。

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

MergeTree主要特点

  • 存储的数据按主键排序,从而能够创建一个小型的稀疏索引来加快数据检索。

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

  • 支持数据副本。

  • 支持数据采样。

建表语句

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 - 引擎名和参数。 ENGINE = MergeTree(), 注意MergeTree 引擎没有参数。
  • ORDER BY — 排序键, 可以是一组列的元组或任意的表达式。 例如: ORDER BY (CounterID, EventDate) 。
  • PARTITION BY — 分区键 ,可选项。
  • TTL即Time To Live,MergeTree提供了可以管理数据表或者列的生命周期的功能。

例:建表语句:
create table t_order_mt(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id)
;

插入数据:

insert into  t_order_mt values
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
(102,'sku_002',2000.00,'2020-06-01 11:00:00'),
(102,'sku_004',2500.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 13:00:00'),
(102,'sku_002',12000.00,'2020-06-01 13:00:00'),
(102,'sku_002',600.00,'2020-06-02 12:00:00');

clickhouse之表引擎_第2张图片

MergeTree之partition by(可选)
1.对于MergeTree引擎来讲,partition by做为一个可选项加不加均可,如果不加的话则是表中的全部数据都在一个分区.

2.MergeTree 是以列文件+索引文件+表定义文件组成的,但是如果设定了分区那么这些文件就会保存到不同的分区目录中,比如以上t_order_mt表中的数据将会保存在这两个目录中其中- *.bin是按列保存数据的文件 , - *.mrk3保存块偏移量 ,- primary.idx保存主键索引

3.关于数据写入与分区合并: 任何一个批次的数据写入都会产生一个临时分区,不会纳入任何一个已有的分区。写入后的某个时刻(大概10-15分钟后),ClickHouse会自动执行合并操作(等不及也可以手动通过optimize执行),把临时分区的数据,合并到已有分区中。

optimize table xxxx final;

clickhouse之表引擎_第3张图片

MergeTree之 primary key(可选)
默认情况下主键跟排序键(由 ORDER BY 子句指定)相同(也可以不相同),因此大部分情况下不需要再专门指定一个 PRIMARY KEY 子句。

1.主键的设定主要依据是查询语句中的where 条件。

2.根据条件通过对主键进行某种形式的二分查找,能够定位到对应的index granularity(索引粒度),避免了全表扫描。(这里简单的说明一下索引粒度指在稀疏索引中两个相邻索引对应数据的间隔,默认是8192)

MergeTree之order by( 必选),建表语句中可以没有primary key ,但是绝对不能没有order by,因为MergeTree后台去重的规则就是按照order by元祖内的元素按顺序排列去重,所以order by是必选项。

要求:主键必须是order by字段的前缀字段。
比如order by 字段是 (id,sku_id) 那么主键必须是id 或者 (id,sku_id).

三:ReplacingMergeTree
ReplacingMergeTree是MergeTree的一个变种,它存储特性完全继承MergeTree,只是多了一个去重的功能。 尽管MergeTree可以设置主键,但是primary key其实没有唯一约束的功能。如果想处理掉重复的数据,可以借助这个ReplacingMergeTree引擎。

  • 关于ReplacingMergeTree去重的时间
    数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以无法预先作出计划。有一些数据可能仍未被处理。

  • 如果表经过了分区,去重只会在分区内部进行去重,不能执行跨分区的去重
    所以ReplacingMergeTree能力有限, ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

  • ReplacingMergeTree去重机制: ReplacingMergeTree() 填入的参数为版本字段,重复数据保留版本字段值最大的。
    如果不填版本字段,默认按照插入顺序保留最后一条

实例演示:
1)建表

create table t_order_rmt(
    id UInt32,
    sku_id String,
    total_amount Decimal(16,2) ,
    create_time  Datetime 
 ) engine =ReplacingMergeTree(create_time)
   partition by toYYYYMMDD(create_time)
   primary key (id)
   order by (id, sku_id);

2)插入数据

insert into  t_order_rmt values
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
(102,'sku_002',2000.00,'2020-06-01 11:00:00'),
(102,'sku_004',2500.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 13:00:00'),
(102,'sku_002',12000.00,'2020-06-01 13:00:00'),
(102,'sku_002',600.00,'2020-06-02 12:00:00');

3)执行查询

 select * from t_order_rmt;

这里可以看到数据按照6-01和6-02分为两个区.
clickhouse之表引擎_第4张图片
4) 手动触发t_order_rmt 中分区内的数据进行合并
OPTIMIZE TABLE t_order_rmt FINAL;

5)触发合并后再次查看数据可以看到已经合并好了
clickhouse之表引擎_第5张图片

结论:

1.实际上是使用order by 字段作为唯一键
2.去重不能跨分区
3.只有同一批插入(新版本)或合并分区时才会进行去重
4.认定重复的数据保留,版本字段值最大的
5.如果版本字段相同则按插入顺序保留最后一笔

四:SummingMergeTree
该引擎继承自 MergeTree。区别在于,当合并 SummingMergeTree 表的数据片段时,ClickHouse 会把所有具有相同order by元祖内的元素的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值。如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度,对于不可加的列,会取一个最先出现的值。

上述ReplacingMergeTree建表的例子引擎如果替换为SummingMergeTree的话在手动触发表的话OPTIMIZE TABLE xxx FINAL;最终的查询结果则是下面按order by内的元祖内的元素(id,order_id)开始聚合的.

clickhouse之表引擎_第6张图片

你可能感兴趣的:(ClickHouse)