Clickhouse中的各种类型的表引擎详解,Log家族类引擎和MergeTree 家族类引擎详解

1.日志引擎

具有最小功能的轻量级引擎。当您需要快速写入许多小表(最多约100万行)并在以后整体读取它们时,该类型的引擎是最有效的。

1.1日志引擎的共同属性为:

  1. 数据存储在磁盘上;
  2. 写数据都是以追加的方式往文件里写数据;
  3. 有支持并发数据访问的锁:在INSERT查询期间,表被锁定,并且其他用于读取和写入数据的查询都等待表解锁。如果没有数据写入查询,那么可以同时执行任意数量的数据读取查询;
  4. 不支持索引:这句话的意思是,select查询的数据范围效率不是很高
  5. 不要原子性的写数据:如果某些操作中断了写操作(例如,异常关闭服务器),则可能会导致表中的数据已损坏。

1.2 日志引擎的不同属性:

TinyLog引擎是该系列中最简单的引擎,功能最差,效率最低。该TinyLog引擎不支持通过单个查询中的多个线程进行并行数据读取。它比支持单个查询并行读取的系列中其他引擎读取数据的速度慢,并且使用几乎与Log引擎一样多的文件描述符,因为它将每一列存储在单独的文件中。仅在简单情况下使用它。(对tinylog引擎的理解:因为使用tinylog引擎数据部分快,不支持 文件的分区,所以单个查询多线程并行的读取数据)

LogStripeLog引擎支持并行数据读取。读取数据时,ClickHouse使用多个线程。每个线程处理一个单独的数据块。该Log引擎使用对表的每列一个单独的文件。StripeLog将所有数据存储在一个文件中。结果,StripeLog引擎使用更少的文件描述符,但是Log引擎在读取数据时提供了更高的效率。

1.3 TinyLog引擎

该表引擎通常与一次写入方法一起使用:一次写入数据,然后根据需要多次读取。例如,您可以将TinyLog-type表用于小批量处理的中间数据。请注意,将数据存储在大量小表中效率很低。

查询在单个流中执行。换句话说,此引擎旨在用于相对较小的表(最多约1,000,000行)。如果您有许多小表,则使用此表引擎很有意义,因为它比日志引擎更简单(需要打开的文件更少)

建表以及表的目录结构:

create table tb_tlog(
uid Int16,
name String,
address String
)
engine=TinyLog;

插入数据:
insert into tb_tlog values (1,'zxx','bj'),(2,'ww','nj'),(1,'ls','tj');
insert into tb_tlog values (3,'zxx','bj'),(4,'ww','nj'),(5,'ls','tj');
insert into tb_tlog values (6,'zxx','bj'),(7,'ww','nj'),(8,'ls','tj');

目录结构:因为tinylog引擎对数部分块,所以在目录中没有块 所以的文件;

-rw-r-----. 1 clickhouse clickhouse 105 Oct 18 22:13 address.bin
-rw-r-----. 1 clickhouse clickhouse 108 Oct 18 22:13 name.bin
-rw-r-----. 1 clickhouse clickhouse  97 Oct 18 22:13 sizes.json
-rw-r-----. 1 clickhouse clickhouse  96 Oct 18 22:13 uid.bin

 1.4 StripLog引擎(数据分块所有的列都在一个文件中:data.bin):

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

1.4.1 写数据

StripeLog 引擎将所有列存储在一个文件中。对每一次 Insert 请求,ClickHouse 将数据块追加在表文件的末尾,逐列写入。

ClickHouse 为每张表写入以下文件:

data.bin — 数据文件。

index.mrk — 带标记的文件。标记包含了已插入的每个数据块中每列的偏移量。

StripeLog 引擎不支持 ALTER UPDATE  ALTER DELETE 操作。

 1.4.2 读数据

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

我们使用两次 INSERT 请求从而在 data.bin 文件中创建两个数据块。

ClickHouse 在查询数据时使用多线程。每个线程读取单独的数据块并在完成后独立的返回结果行。这样的结果是,大多数情况下,输出中块的顺序和输入时相应块的顺序是不同的

 1.5 Log引擎(数据分块记录偏移量)

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

2.MergeTree家族引擎:

MergeTree系列的表引擎是ClickHouse数据存储功能的核心。它们提供了用于弹性和高性能数据检索的大多数功能:列存储,自定义分区,稀疏的主索引,辅助数据跳过索引等。

基本MergeTree表引擎可以被认为是单节点ClickHouse实例的默认表引擎,因为它在各种用例中通用且实用。

对于生产用途,ReplicatedMergeTree是必经之路,因为它为常规MergeTree引擎的所有功能增加了高可用性。一个额外的好处是在数据提取时自动进行重复数据删除,因此如果插入过程中出现网络问题,该软件可以安全地重试。

MergeTree系列的所有其他引擎为某些特定用例添加了额外的功能。通常,它是作为后台的其他数据操作实现的。

MergeTree引擎的主要缺点是它们很重。因此,典型的模式是没有太多。如果您需要许多小表(例如用于临时数据),请考虑使用Log engine family

主要特点:

  1. 存储按主键排序的数据。

这使您可以创建一个小的稀疏索引,以帮助更快地查找数据。

  1. 如果指定了分区键,则可以使用分区

ClickHouse支持的某些分区操作比对相同数据,相同结果的常规操作更有效。ClickHouse还会自动切断在查询中指定了分区键的分区数据。这也提高了查询性能。

  1. 数据复制支持。

ReplicatedMergeTree表族提供数据复制。有关更多信息.

  1. 数据采样支持。

如有必要,可以在表中设置数据采样方法。

2.1 MergeTree引擎:

MergeTree系列中的引擎旨在将大量数据插入表中。数据快速地逐个部分写入表中,然后应用规则在后台合并这些部分。这种方法比插入期间连续重写存储中的数据效率更高。

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

    这使您可以创建一个较小的稀疏索引,以帮助更快地查找数据。

  • 如果指定了分区键,则可以使用分区

    ClickHouse支持某些分区操作,这些操作比对相同数据,相同结果的常规操作更有效。ClickHouse还会自动切断在查询中指定了分区键的分区数据。这也提高了查询性能。

  • 数据复制支持。

    ReplicatedMergeTree表族提供数据复制。有关更多信息,请参见数据复制

  • 数据采样支持。

    如有必要,可以在表中设置数据采样方法。

 每批次的插入数据作为一个基础单元进行分区,区内数据按照指定的字段进行排序

合并多次插入的分区:  合并之后会生成新的文件,当时间达到一定的阈值的时候,之间的文件就会自动删除;

 optimize table tb_merge_tree ;

2.2ReplacingMergeTree引擎

这个引擎是在 MergeTree 的基础上,添加了“处理重复数据”的功能,该引擎和MergeTree的不同之处在于它会删除具有相同主键的重复项。数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以你无法预先作出计划。有一些数据可能仍未被处理。因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。

特点:

在数据合并的时候 根据主键分区内自动的去重主键重复的数据,我们可以指定一个字段作为数据的版本,当去除重复数据的时候保留版本大的数据!

CH内部会自动的合并数据并去重重复数据 ,当然我们也可以手动的执行合并,但是每次处罚命令只能合并一个分区的数据,一般情况下等待他自己合并数据即可! 所以我们无法保证表中不存在重复主键数据

 建表:

create table tb_rep_merge_tree(
id Int8 ,
name String ,
ctime Date ,
version UInt8 
)
engine=ReplacingMergeTree(version)  --这里面的参数,指得是版本数:ReplacingMergeTree引擎在合并的时候会自动的去重,并且只保留指定字段的最大版本数
order by id 
partition by name 

 插入数据:

insert into tb_rep_merge_tree values (1, 'a','2020-08-05', 20);
insert into tb_rep_merge_tree values (1, 'b','2020-08-05', 30);
insert into tb_rep_merge_tree values (1, 'a','2020-08-05', 20);
insert into tb_rep_merge_tree values (1, 'a','2020-08-05', 30);
insert into tb_rep_merge_tree values (1, 'b','2020-08-05', 10);

查看结果:

手动合并分区 因为每次合并只能合并两个文件,所以手动执行两次:

optimize  table  tb_rep_merge_tree ;

结果:

分析:从以上结果可以看出,在合并的过程中,会删除主键重复的数据,只保留一个指定字段为数据版本的最大版本数据;

2.3CollapsingMergeTree 引擎

ClickHouse实现了CollapsingMergeTree来消除ReplacingMergeTree的限制(只删除小版本字段,只保留最大版本数据)。该引擎要求在建表语句中指定一个标记列Sign,后台Compaction时会将主键相同、Sign相反的行进行折叠,也即删除。

CollapsingMergeTree将行按照Sign的值分为两类:Sign=1的行称之为状态行,Sign=-1的行称之为取消行。

每次需要新增状态时,写入一行状态行;需要删除状态时,则写入一行取消行。在后台Compaction时,状态行与取消行会自动做折叠(删除)处理。而尚未进行Compaction的数据,状态行与取消行同时存在。

因此为了能够达到主键折叠(删除)的目的,需要业务层进行适当改造:

1) 执行删除操作需要写入取消行,而取消行中需要包含与原始状态行一样的数据(Sign列除外)。所以在应用层需要记录原始状态行的值,或者在执行删除操作前先查询数据库获取原始状态行;

2)由于后台Compaction时机无法预测,在发起查询时,状态行和取消行可能尚未被折叠;另外,ClickHouse无法保证primary key相同的行落在同一个节点上,不在同一节点上的数据无法折叠因此在进行count(*)、sum(col)等聚合计算时,可能会存在数据冗余的情况。为了获得正确结果,业务层需要改写SQL,count()sum(col)分别改写为sum(Sign)sum(col * Sign)

CollapsingMergeTree虽然解决了主键相同的数据即时删除的问题

实例:

创建表:

create table tb_c_mt(
   UserID UInt64,
    PageViews UInt8,
    Duration UInt8,
    Sign Int8
 )
 engine=CollapsingMergeTree(Sign)  --这个参数值得是标记字段
 order by UserID;

插入数据:

 --入状态行  数据
 INSERT INTO tb_c_mt VALUES (4324182021466249495, 5, 146, 1);
  INSERT INTO tb_c_mt VALUES (4324182021466249495, 5, 146, 1);
 --后插入取消行数据
 INSERT INTO tb_c_mt VALUES (4324182021466249495, 5, 146, -1);

执行:select * from tb_c_mt;

合并之后的数据:optimize table tb_c_mt;

查询的结果,说明我们查询的结果就是将标记为-1 的这行数据的上一行数据删除,

 

注意:

CollapsingMergeTree虽然解决了主键相同的数据即时删除的问题,但是状态持续变化且多线程并行写入情况下,状态行与取消行位置可能乱序,导致无法正常折叠。只有保证老的状态行在在取消行的上面, 新的状态行在取消行的下面! 但是多线程无法保证写的顺序!

2.4 VersionedCollapsingMergeTree

取消字段和数据版本同事使用,避免取消行数据无法删除的问题

为了解决CollapsingMergeTree乱序写入情况下无法正常折叠问题VersionedCollapsingMergeTree表引擎在建表语句中新增了一列Version,用于在乱序情况下记录状态行与取消行的对应关系。主键相同,且Version相同、Sign相反的行,在Compaction时会被删除。

与CollapsingMergeTree类似, 为了获得正确结果,业务层需要改写SQL,将count()、sum(col)分别改写为sum(Sign)、sum(col * Sign)。

 

实例:

创建表以及插入数据:

 

 //VersionedCollapsingMergeTree
 create table tb_v_c_mt(
 uid Int64,
 name String,
 sign Int8,
 version Int8
 )
 engine=VersionedCollapsingMergeTree(sign,version) --参数值得是标记字段和版本字段
 order by uid;
 insert into tb_v_c_mt values(1001,'zss',-1,1);
   insert into tb_v_c_mt values(1002,'zss',1,4);
    insert into tb_v_c_mt values(1001,'zss',1,3);
	 insert into tb_v_c_mt values(1001,'zss',1,2);
	   insert into tb_v_c_mt values(1001,'zss',1,1);

 结果展示:

结果分析:

VersionedCollapsingMergeTree表引擎解决了CollapsingMergeTree乱序写入情况下无法正常折叠问题在建表语句中新增了一列Version,用于在乱序情况下记录状态行与取消行的对应关系。主键相同,且Version相同、Sign相反的行,在Compaction时会被删除。

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值