Clickhouse表引擎-日志系列

1、表引擎的介绍

 Clickhouse的表引擎类似MySQL的表引擎,表引擎决定了如何存储表的数据,主要包含如下特性:

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

 表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎使用的相关参数。

注意:表引擎的名称大小写敏感

2、引擎类型

  1. Log类型(日志类型)
  2. MergeTree类型(合并树类型)
  3. Integration Engines(集成类型)
  4. Special Engines(其他特定类型)
  5. Virtual Columns(虚拟列)

3、日志引擎系列

 这类引擎是为了需要写入许多小数据量(少于100W)的场景而开发的,Log 家族的引擎可以将数据存储在S3或者HDFS分布式文件系统上,这系列的引擎有:
– Log
– TinyLog
– StripeLog

3.1、存在如下的特点:

  • 数据存储在磁盘上
  • 写入时将数据追加在文件末尾
  • 不支持变更操作
  • 不支持索引,这个意味着范围查询效率不高
  • 非原子写入数据,如果有些线程影响写操作将会导致表数据损坏,比如在写过程服务器异常停止
  • 支持表锁,有写入数据的时候,表是锁的。其他读写查询都需要等待表锁释放,如果没有数据写入,可以执行并发查询。

3.2、差异点

  • TinyLog 引擎是该系列中最简单的引擎并且提供了最少的功能和最低的性能。TinyLog 引擎不支持单个查询下的多线程查询,它比其余两种支持并行读取的引擎的读取速度更慢,并且使用了和 Log 引擎同样多文件的描述符。因为它的每一列存储在不同的文件中,你可以在简单的低负载的情景下使用它。
  • Log 引擎为表中的每一列使用不同的文件。StripeLog 将所有的数据存储在一个文件中。因此 StripeLog 引擎在操作系统中使用更少的描述符,但是 Log 引擎提供更高的读性能。
  • Log和StripeLog引擎支持表锁,有写入数据的时候,表是锁的。其他读写查询都需要等待表锁释放,如果没有数据写入,可以执行并发查询。
  • 并行读取数据,在读取数据时,ClickHouse 使用多线程。 每个线程处理不同的数据块。

4、Log

 Log 与 TinyLog 的不同之处在于,标记 的小文件与列文件存在一起。这些标记记录每个数据块,并且包含偏移量,这些偏移量指示从哪里开始读取文件以便跳过指定的行数。这使得可以在多个线程中读取表数据。对于并发数据访问,可以同时执行读取操作,而写入操作则阻塞读取和其它写入。Log引擎不支持索引。同样,如果写入表失败,则该表将被破坏,并且从该表读取将返回错误。Log引擎适用于临时数据,write-once 表以及测试或演示目的。

5、StripeLog

 在你需要写入许多小数据量(小于一百万行)的表的场景下使用这个引擎。

5.1、建表

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    column1_name [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    column2_name [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = StripeLog

5.2、写数据

 StripeLog 引擎将所有列存储在一个文件中。对每一次Insert请求,ClickHouse将数据块追加在表文件的末尾,逐列写入。
ClickHouse为每张表写入以下文件:
– data.bin — 数据文件。
– index.mrk — 带标记的文件。标记包含了已插入的每个数据块中每列的偏移量。

注意:StripeLog 引擎不支持 ALTER UPDATE 和 ALTER DELETE 操作。

5.3、读数据

 带标记的文件使得ClickHouse可以并行的读取数据。这意味着 SELECT 请求返回行的顺序是不可预测的。使用 ORDER BY 子句对行进行排序

5.4、示例演示

建表

CREATE TABLE stripe_log_table
(
    timestamp DateTime,
    message_type String,
    message String
)
ENGINE = StripeLog

插入数据

INSERT INTO stripe_log_table VALUES (now(),'REGULAR','The first regular message');
INSERT INTO stripe_log_table VALUES (now(),'REGULAR','The second regular message'),(now(),'WARNING','The first warning message');
INSERT INTO stripe_log_table VALUES (now(),'REGULAR','The second regular message');

我们使用三次INSERT请求从而在data.bin文件中创建两个数据块。
ClickHouse 在查询数据时使用多线程。每个线程读取单独的数据块并在完成后独立的返回结果行。这样的结果是,大多数情况下,输出中块的顺序和输入时相应块的顺序是不同的。例如:

SELECT * FROM stripe_log_table;

得到的结果是这样的:

┌───────────timestamp─┬─message_type─┬─message───────────────────┐
│ 2022-03-14 09:58:04 │ REGULAR      │ The first regular message │
└─────────────────────┴──────────────┴───────────────────────────┘
┌───────────timestamp─┬─message_type─┬─message────────────────────┐
│ 2022-03-14 10:05:44 │ REGULAR      │ The second regular message │
│ 2022-03-14 10:05:44 │ WARNING      │ The first warning message  │
└─────────────────────┴──────────────┴────────────────────────────┘
┌───────────timestamp─┬─message_type─┬─message────────────────────┐
│ 2022-03-14 10:02:09 │ REGULAR      │ The second regular message │
└─────────────────────┴──────────────┴────────────────────────────┘

对结果排序(默认增序):

SELECT * FROM stripe_log_table ORDER BY timestamp asc;

得到的结果是这样的:

┌───────────timestamp─┬─message_type─┬─message───────────────────┐
│ 2022-03-14 09:58:04 │ REGULAR      │ The first regular message │
└─────────────────────┴──────────────┴───────────────────────────┘
┌───────────timestamp─┬─message_type─┬─message────────────────────┐
│ 2022-03-14 10:02:09 │ REGULAR      │ The second regular message │
└─────────────────────┴──────────────┴────────────────────────────┘
┌───────────timestamp─┬─message_type─┬─message────────────────────┐
│ 2022-03-14 10:05:44 │ REGULAR      │ The second regular message │
│ 2022-03-14 10:05:44 │ WARNING      │ The first warning message  │
└─────────────────────┴──────────────┴────────────────────────────┘

6、TinyLog

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

并发数据访问不受任何限制:
– 如果同时从表中读取并在不同的查询中写入,则读取操作将抛出异常
– 如果同时写入多个查询中的表,则数据将被破坏。

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