1 概述

​ 表引擎在ClickHouse中的作用十分关键,表引擎有如下作用:

​ (1)数据如何存储,存在哪,数据写到哪, 怎样读取数据;

​ (2)支持哪些查询以及如何支持;

​ (3)并发数据访问;

​ (4)索引的使用;

​ (5)是否可以执行多线程的请求;

​ (6)数据如何同步。

2 表引擎系列

2.1 MergeTree系列

​ MergeTree系列是对于高负载任务的最通用和最实用的表引擎。这些引擎共享的属性是快速数据插入和后续的后台数据处理。想要高效地一批批写入数据片段,并希望这些数据片段在后台按照一定规则合并。相比在插入时不断修改(重写)数据进存储,这种策略会高效很多。MergeTree系列引擎支持数据复制、分区和其他引擎不支持的特性。有如下特点:①数据按照主键进行排序;②可以使用分区(如果指定了主键);③支持数据副本;④支持数据采样

2.1.1 MergeTree

​ MergeTree 引擎支持索引,通过主键和日期来构建索引, 同时提供 数据的实时更新能力. 这是目前 ClickHouse处理能力最好的引擎。

​ 注意:①不能和Merge 引擎相混淆。

​ ②MergeTree虽然有主键索引,但是其主要作用是加速查询,而不是类似MySQL等数据库用来保持记录唯一。即便在Compaction完成后,主键相同的数据行也仍旧共同存在。

​ 建表语句如下

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()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]

​ 参数说明:

参数 说明
ENGINE = MergeTree() ENGINE:引擎名和参数
PARTITION BY expr PARTITION BY:分区键,按月分区采用“YYYYMM”格式,可以使用toYYYYMM (date_column)表达式,date_column类型必须是Date
ORDER BY expr ORDER BY:排序键,列的元组或任意表达式 (字段的组合), 或者单独的表达式。如:ORDER BY (CounterID, EventDate)
PRIMARY KEY expr PRIMARY KEY:主键,需要与排序键字段不同,默认主键与排序键相同
SAMPLE BY expr SAMPLE BY:抽样表达式,要用抽样表达式,主键必须包含这个表达式
TTL expr [DELETE |TO DISK ‘xxx’ TO VOLUME ‘xxx’], … TTL:指定行存储时间和定义磁盘与卷之间自动部件移动逻辑的规则列表。如:TTL create_time + INTERVAL 1 MONTH(表数据的生命周期为期一个月 )它的含义是当ClickHouse合并数据分区时, 会根据create_time这一列的时间数据以及之后一个月的这样一周期内的数据进行保存,不在这一时间段内的数据,ck就是主动删除分区目录下的列文件
SETTINGS name=value, … SETTINGS:影响MergeTree性能的额外参数
①index_granularity:索引粒度,索引键相邻标记间的数据行数,默认8192
②use_minimalistic_part_header_in_zookeeper:在Zookeeper中的存储方式
③min_merge_bytes_to_use_direct_io:使用直接I/O来操作磁盘的合并操作时的最小数据量

​ 测试:test_mt表的主键为(id, create_time),并且按照主键进行存储排序,按照create_time进行数据分区,根据create_time这一列的时间数据保留最近一个月。

CREATE TABLE test_mt ( \id UInt16, \create_time Date, \comment Nullable(String) \
) ENGINE = MergeTree() \
PARTITION BY create_time \
ORDER BY  (id, create_time) \
PRIMARY KEY (id, create_time) \
TTL create_time + INTERVAL 1 MONTH \
SETTINGS index_granularity=8192;

​ 插入数据

insert into test_mt values(0, '2020-01-01', null);
insert into test_mt values(0, '2020-01-01', null);
insert into test_mt values(1, '2020-01-02', null);
insert into test_mt values(2, '2020-01-03', null);

​ 查询数据

SELECT count(*)
FROM test_mt
┌─count()─┐
│       4 │
└─────────┘SELECT *
FROM test_mt ┌─id─┬─create_time─┬─comment─┐
│  2 │  2020-01-03 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  1 │  2020-01-02 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  0 │  2020-01-01 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  0 │  2020-01-01 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘

​ 可以发现虽然主键id、create_time相同的数据只有3条数据,但是结果却有4行。因为MergeTree采用类似LSM tree的结构,很多存储层处理逻辑直到Compaction期间才会发生。因此强制后台compaction执行

optimize table test_mt final;

​ 再次查询,发现没有数据了。

SELECT count(*)
FROM test_mt ┌─count()─┐
│       0 │
└─────────┘

​ 是因为TTL的原因,我们在表上加了TTL当表内的数据过期时, ClickHouse会删除所有对应的行。如果是列上加TTL,当列字段中的值过期时, ClickHouse会将它们替换成数据类型的默认值。如果分区内,某一列的所有值均已过期,则ClickHouse会从文件系统中删除这个分区目录下的列文件。

​ 如果没有加TTL的查询出来应该是如下所示

SELECT count(*)
FROM test_mt ┌─count()─┐
│       4 │
└─────────┘select * from test_mt;
┌─id─┬─create_time─┬─comment─┐
│  2 │  2020-01-03 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  1 │  2020-01-02 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  0 │  2020-01-01 │ ᴺᵁᴸᴸ    │
│  0 │  2020-01-01 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘

2.1.2 ReplacingMergeTree

​ ReplacingMergeTree在MergeTree的基础上,添加了处理重复数据的功能,也就是会删除具有相同主键的重复项,这就是与MergeTree的不同之处。

​ 注意:数据的去重是在合并的过程中出现的,合并会在未知的时间在后台运行,所以无法预先做出计划。所以可能有一些数据任未被处理,因此ReplacingMergeTree适用于在后台清理重复数据以节省空间,但是不能保证没有重复的数据出现。

​ 语法:

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],...
) ENGINE = ReplacingMergeTree([ver])
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

​ 参数说明:ENGINE = ReplacingMergeTree([ver]),这个ver是版本列,类型是UInt*,Date或者DateTime,合并的时候ReplacingMergeTree从具有相同主键的行中选择一行留下,如果ver列没有指定,选择最后一条,如果ver列已指定,选择ver最大的版本。其他的参考MergeTree的

​ 测试:

CREATE TABLE test_rmt (\id UInt16,\create_time Date,\comment Nullable(String)\
) ENGINE = ReplacingMergeTree()\PARTITION BY create_time\ORDER BY  (id, create_time)\PRIMARY KEY (id, create_time)\TTL create_time + INTERVAL 1 MONTH\SETTINGS index_granularity=8192;

​ 插入数据:

insert into test_rmt values(0, '2020-05-01', null);
insert into test_rmt values(0, '2020-05-01', null);
insert into test_rmt values(1, '2020-05-02', null);
insert into test_rmt values(2, '2020-05-03', null);

​ 查询结果:

SELECT count(*)
FROM test_rmt ┌─count()─┐
│       4 │
└─────────┘SELECT *
FROM test_rmt ┌─id─┬─create_time─┬─comment─┐
│  1 │  2020-05-02 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  2 │  2020-05-03 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  0 │  2020-05-01 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  0 │  2020-05-01 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘

​ 可以发现数据还是4条,强制后台compaction

optimize table test_rmt final;

​ 再次查询

SELECT count(*)
FROM test_rmt ┌─count()─┐
│       3 │
└─────────┘SELECT *
FROM test_rmt ┌─id─┬─create_time─┬─comment─┐
│  1 │  2020-05-02 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  2 │  2020-05-03 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘
┌─id─┬─create_time─┬─comment─┐
│  0 │  2020-05-01 │ ᴺᵁᴸᴸ    │
└────┴─────────────┴─────────┘

​ 总结:虽然ReplacingMergeTree提供了主键去重的能力,但是仍旧有以下缺点:①在没有彻底optimize之前,可能无法达到主键去重的效果,部分数据已经去重,部分没有去重②在分布式情况下,相同primary key的数据可能被sharding到不同节点上,不同shard间可能无法去重③无法预测optimize具体执行时间点④海量数据下要手动执行optimize需要消耗大量时间,无法满足业务即时查询的需求

2.1.3 SummingMergeTree

​ SummingMergeTree与MergeTree不区别在与当合并SummingMergeTree表的数据片段时,会把相同主键的行合并为一行,这一行包含了被合并的行中具有数值数据类型的列的汇总值,对于不可加的列会取出一个最先出现的值。如果相同的主键对应大量的行,可以显著减少存储空间并加快数据查询的速度。

​ 语法:

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],...
) ENGINE = SummingMergeTree([columns])
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

​ 参数说明:ENGINE = SummingMergeTree([columns]):[columns]表示将要被汇总的列的列名的元组。

​ 测试:

CREATE TABLE test_smt(\date Date,\name String,\money UInt16,\not_sum UInt16\
)\
ENGINE = SummingMergeTree(money)\
PARTITION by date \
ORDER by (date,name);

​ 插入数据:

insert into test_smt values ('2020-05-01', 'zs', 6, 1);
insert into test_smt values ('2020-05-01', 'ls', 8, 2);
insert into test_smt values ('2020-05-02', 'ww', 6, 3);
insert into test_smt values ('2020-05-02', 'ww', 8, 4);
insert into test_smt values ('2020-05-03', 'zl', 6, 5);

​ 查询:

SELECT *
FROM test_smt ┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-02 │ ww   │     8 │       4 │
└────────────┴──────┴───────┴─────────┘
┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-01 │ zs   │     6 │       1 │
└────────────┴──────┴───────┴─────────┘
┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-03 │ zl   │     6 │       5 │
└────────────┴──────┴───────┴─────────┘
┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-01 │ ls   │     8 │       2 │
└────────────┴──────┴───────┴─────────┘
┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-02 │ ww   │     6 │       3 │
└────────────┴──────┴───────┴─────────┘

​ 通过GROUP BY进行聚合查询

SELECT date, name, sum(money), min(not_sum)
FROM test_smt
GROUP BY date, name┌───────date─┬─name─┬─sum(money)─┬─min(not_sum)─┐
│ 2020-05-01 │ ls   │          8 │            2 │
│ 2020-05-02 │ ww   │         14 │            3 │
│ 2020-05-03 │ zl   │          6 │            5 │
│ 2020-05-01 │ zs   │          6 │            1 │
└────────────┴──────┴────────────┴──────────────┘

​ 强制compaction

optimize table test_smt final;

​ 再次查询

SELECT *
FROM test_smt ┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-03 │ zl   │     6 │       5 │
└────────────┴──────┴───────┴─────────┘
┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-01 │ ls   │     8 │       2 │
│ 2020-05-01 │ zs   │     6 │       1 │
└────────────┴──────┴───────┴─────────┘
┌───────date─┬─name─┬─money─┬─not_sum─┐
│ 2020-05-02 │ ww   │    14 │       3 │
└────────────┴──────┴───────┴─────────┘

2.1.4 ClollapsingMergeTree

​ ClollapsingMergeTree实现了对ReplacingMergeTree功能的限制,在建表语句中指定一个标记列sign,后台Compaction时会将主键相同,sign相反的行进行删除。ClollapsingMergeTree将行安装sign的值分为两类:sign=1为状态行,sign=-1位取消行。每次需要新增状态时,写入一行状态行,需要删除状态时,写入一行取消行。后台在Compaction时,状态行与取消行会自动做折叠(删除),而尚未进行Compaction的数据,状态行与取消行同时存在。

​ 为了能够达到主键折叠(删除)的目的,对业务层进行适当改造:①执行删除操作需要写入取消行,而取消行中需要包含与原始状态行主键一样的数据(Sign列除外)。所以在应用层需要记录原始状态行的值,或者在执行删除操作前先查询数据库获取原始状态行。②由于后台Compaction时机无法预测,在发起查询时,状态行和取消行可能尚未被折叠;另外,ClickHouse无法保证primary key相同的行落在同一个节点上,不在同一节点上的数据无法折叠。因此在进行count(*)、sum(col)等聚合计算时,可能会存在数据冗余的情况。为了获得正确结果,业务层需要改写SQL,将count()、sum(col)分别改写为sum(Sign)、sum(col * Sign)。

​ 测试:

CREATE TABLE test_cmt1(\UserID UInt64,\PageViews UInt8,\Duration UInt8,\Sign Int8\
)\
ENGINE = CollapsingMergeTree(Sign)\
ORDER BY UserID;

​ 插入状态行,sign列的值为1

INSERT INTO test_cmt1 VALUES (123456, 6, 88, 1);

​ 插入一行取消行,用于抵消上述状态行。sign列的值为-1,其余值与状态行一致;并且插入一行主键相同的新状态行,用来将PageViews从6更新至7,将Duration从888更新为889.

INSERT INTO test_cmt1 VALUES (123456, 6, 88, -1), (123456, 7, 90, 1);

​ 查询数据:可以看到未Compaction之前,状态行与取消行共存。

SELECT *
FROM test_cmt1 ┌─UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 123456 │         6 │       88 │    1 │
└────────┴───────────┴──────────┴──────┘
┌─UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 123456 │         6 │       88 │   -1 │
│ 123456 │         7 │       90 │    1 │
└────────┴───────────┴──────────┴──────┘
 为了获取正确的sum值,需要改写SQL: sum(PageViews) => sum(PageViews * Sign)、 sum(Duration) => sum(Duration * Sign)
SELECT UserID, sum(PageViews * Sign) AS PageViews, sum(Duration * Sign) AS Duration
FROM test_cmt1
GROUP BY UserID
HAVING sum(Sign) > 0┌─UserID─┬─PageViews─┬─Duration─┐
│ 123456 │         7 │       90 │
└────────┴───────────┴──────────┘

​ 强制后台Compaction

optimize table test_cmt1 final;

​ 再次查询,可以看到状态行、取消行已经被折叠,只剩下最新的一行状态行。

SELECT *
FROM test_cmt1 ┌─UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 123456 │         7 │       90 │    1 │
└────────┴───────────┴──────────┴──────┘

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

CREATE TABLE test_cmt2(\UserID UInt64,\PageViews UInt8,\Duration UInt8,\Sign Int8\
)\
ENGINE = CollapsingMergeTree(Sign)\
ORDER BY UserID;

​ 先插入取消行,然后后插入状态行

INSERT INTO test_cmt2 VALUES (123456, 6, 88, -1);
INSERT INTO test_cmt2 VALUES (123456, 6, 88, 1);

​ 强制Compaction

optimize table test_cmt2 final;

​ 查询

select * from test_cmt2;

​ 可以看到即便Compaction之后也无法进行主键折叠: 2行数据仍旧都存在。

SELECT *
FROM test_cmt2 ┌─UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 123456 │         6 │       88 │   -1 │
│ 123456 │         6 │       88 │    1 │
└────────┴───────────┴──────────┴──────┘

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

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

2.1.5 AggregatingMergeTree

​ AggregatingMergeTree与MergeTree的区别在于会进行预先的聚合,用于提升聚合计算的性能。与SummingMergeTree的区别在于SummingMergeTree对于非主键列进行sum聚合,而AggregatingMergeTree则可以指定各种聚合函数。

​ AggregatingMergeTree需要结合物化视图或者ClickHouse的特殊数据类型ArrregateFunction一起使用,在insert写入的时候需要使用-State语法,在select查询的时候使用-Merge语法。

​ 语法:

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],...
) ENGINE = AggregatingMergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[TTL expr]
[SETTINGS name=value, ...]

​ (1)结合物化视图

CREATE TABLE test_amt1(\UserID UInt64,\CounterID UInt8,\StartDate Date,\Sign Int8\
)\
ENGINE = CollapsingMergeTree(Sign)\
ORDER BY UserID;

​ 对test_amt建立物化视图,进行预先聚合。预先聚合使用的函数分别为: sumState, uniqState。对应于写入语法-State.

CREATE MATERIALIZED VIEW test_amt1_view\
ENGINE = AggregatingMergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate)\
AS SELECT\CounterID,\StartDate,\sumState(Sign)    AS Visits,\uniqState(UserID) AS Users\
FROM test_amt1\
GROUP BY CounterID, StartDate;

​ 插入数据

INSERT INTO test_amt1 VALUES(123, 0, '2020-05-01', 3);
INSERT INTO test_amt1 VALUES(123, 1, '2020-05-01', 3);
INSERT INTO test_amt1 VALUES(111, 2, '2020-05-02', 2);

​ 对物化视图进行最终的聚合操作。使用的聚合函数为 sumMerge, uniqMerge。

SELECT \StartDate, \sumMerge(Visits) AS Visits, \uniqMerge(Users) AS Users\
FROM test_amt1_view \
GROUP BY StartDate\
ORDER BY StartDate ASC┌──StartDate─┬─Visits─┬─Users─┐
│ 2020-05-01 │      6 │     1 │
│ 2020-05-02 │      2 │     1 │
└────────────┴────────┴───────┘

​ 普通函数 sum, uniq不再可以使用,会报错: Illegal type AggregateFunction(sum, Int8) of argument

​ (2)配合特殊数据类型AggregateFunction使用

CREATE TABLE test_amt2(\CounterID UInt8,\StartDate Date,\Money UInt64,\UserID UInt64\
) ENGINE = MergeTree() \
PARTITION BY toYYYYMM(StartDate) \
ORDER BY (CounterID, StartDate);

​ 插入数据

INSERT INTO test_amt2 VALUES(111, '2020-05-01', 10, 1);
INSERT INTO test_amt2 VALUES(111, '2020-05-01', 12, 5);
INSERT INTO test_amt2 VALUES(122, '2020-05-02', 9, 2);

​ 建立预先聚合表,其中UserID一列的类型为:AggregateFunction(uniq, UInt64)

CREATE TABLE test_amt2_agg(\CounterID UInt8,\StartDate Date,\Money AggregateFunction(sum, UInt64),\UserID AggregateFunction(uniq, UInt64)\
) ENGINE = AggregatingMergeTree() \
PARTITION BY toYYYYMM(StartDate) \
ORDER BY (CounterID, StartDate);

​ 从明细表中读取数据,插入聚合表,子查询中使用的聚合函数为 uniqState

INSERT INTO test_amt2_agg SELECT \CounterID, \StartDate, \sumState(Money),\uniqState(UserID)\
FROM test_amt2 \
GROUP BY \CounterID, \StartDate

​ 注意:不能使用普通insert语句向AggregatingMergeTree中插入数据。会报错:Cannot convert UInt64 to AggregateFunction(uniq, UInt64)

​ 从聚合表中查询,select中使用的聚合函数为uniqMerge

SELECT CounterID,StartDate,sumMerge(Money),uniqMerge(UserID) AS state\
FROM test_amt2_agg \
GROUP BY \CounterID, \StartDateSELECT CounterID, StartDate, sumMerge(Money), uniqMerge(UserID) AS state
FROM test_amt2_agg
GROUP BY CounterID, StartDate┌─CounterID─┬──StartDate─┬─sumMerge(Money)─┬─state─┐
│       122 │ 2020-05-02 │               9 │     1 │
│       111 │ 2020-05-01 │              22 │     2 │
└───────────┴────────────┴─────────────────┴───────┘

2.2 Log系列

​ Log系列表引擎功能相对简单,轻量级引擎主要用于快速写入小表(1百万行左右的表),然后全部读出的场景。

​ 特点:

​ (1)数据被顺序append写到磁盘上。

​ (2)不支持delete、update。

​ (3)不支持index。

​ (4)不支持原子性写。

​ (5)insert会阻塞select操作。

​ TinyLog,StripLog,Log区别如下:①TinyLog:不支持并发读取数据文件,查询性能较差;格式简单,适合用来暂存中间数据。②StripLog:支持并发读取数据文件,查询性能比TinyLog好;将所有列存储在同一个大文件中,减少了文件个数。③Log:支持并发读取数据文件,查询性能比TinyLog好;每个列会单独存储在一个独立文件中。

2.2.1 TinyLog

​ 最简单的表引擎,用于将数据存储在磁盘上。每列都存储在单独的压缩文件中,写入时,数据将附加到文件末尾。该引擎没有并发控制,如果同时从表中读取和写入数据,则读取操作将抛出异常;如果同时写入多个查询中的表,则数据将被破坏。
不支持索引。

​ 测试:

CREATE TABLE test_tl (\id UInt16,\name String)\
ENGINE=TinyLog;

​ 插入数据:

INSERT INTO test_tl (id, name) values (1, 'zs');

​ 进入ClickHouse的test_tl表的数据存储目录

[root@ambari01 test_tl]# cd /data/clickhouse/data/test/test_tl[root@ambari01 test_tl]# ll
total 12
-rw-r----- 1 clickhouse hadoop 28 May 22 18:07 id.bin
-rw-r----- 1 clickhouse hadoop 29 May 22 18:07 name.bin
-rw-r----- 1 clickhouse hadoop 64 May 22 18:07 sizes.json

​ id.bin和name.bin是压缩过的对应的列的数据,sizes.json 中记录了每个 *.bin 文件的大小。

[root@ambari01 test_tl]# cat sizes.json
{"yandex":{"id%2Ebin":{"size":"28"},"name%2Ebin":{"size":"29"}}}

2.3 Integration系列

​ 该系统表引擎主要用于将外部数据导入到ClickHouse中,或者在ClickHouse中直接操作外部数据源。

2.3.1 Kafka

​ 将Kafka Topic中的数据直接导入到ClickHouse。

2.3.2 MySQL

​ 将Mysql作为存储引擎,直接在ClickHouse中对MySQL表进行select等操作。

2.3.3 JDBC/ODBC

​ 通过指定jdbc、odbc连接串读取数据源。

2.3.4 HDFS

​ 直接读取HDFS上的特定格式的数据文件;

2.4 Special系列

​ Special系列的表引擎,是为了特定场景而定制的,不做详述。

​ Memory:将数据存储在内存中,重启后会导致数据丢失。查询性能极好,适合于对于数据持久性没有要求的1亿一下的小表。在ClickHouse中,通常用来做临时表。

​ Buffer:为目标表设置一个内存buffer,当buffer达到了一定条件之后会flush到磁盘。

​ File:直接将本地文件作为数据存储。

​ Null:写入数据被丢弃、读取数据为空。

ClickHouse表引擎相关推荐

  1. 【clickhouse】ClickHouse表引擎 MergeTree 数据生命周期

    1.概述 转载:ClickHouse表引擎 MergeTree 数据生命周期 TTL(Time To Live)表示数据的存活时间,在 Merge 中可以为某个字段或者整个表设置TTL. 如果设置列级 ...

  2. 【clickhouse】ClickHouse表引擎 MergeTree 索引与数据存储方式 一级索引 二级索引

    1.概述 转载:ClickHouse表引擎 MergeTree 索引与数据存储方式 2.一级索引 MergeTree 主键使用 primary key 定义,定义主键后,会将数据依据 index_gr ...

  3. clickhouse表引擎-合并树系列

    目录 1 clickhouse表引擎-合并树系列简介 2 MergeTree引擎 2.1 建表语法 2.2 创建最简单的MergerTree引擎表 2.3 插入数据 2.4 查看目录结构 2.5 指定 ...

  4. ClickHouse表引擎到底怎么选

    引言 表引擎在ClickHouse中的作用十分关键,直接决定了数据如何存储和读取.是否支持并发读写.是否支持index.支持的query种类.是否支持主备复制等. ClickHouse提供了大约28种 ...

  5. 大数据培训ClickHouse表引擎

    表引擎 表引擎(即表的类型)决定了: 1)数据的存储方式和位置,写到哪里以及从哪里读取数据 2)支持哪些查询以及如何支持. 3)并发数据访问. 4)索引的使用(如果存在). 5)是否可以执行多线程请求 ...

  6. 3、ClickHouse表引擎-MergeTree引擎

    ClickHouse系列文章 1.ClickHouse介绍 2.clickhouse安装与简单验证(centos) 3.ClickHouse表引擎-MergeTree引擎 4.clickhouse的L ...

  7. ClickHouse 表引擎 ClickHouse性能调优

    https://clickhouse.com/ 引子 什么是"更快"? 顺序读/写吞吐量? 随机读/写延迟? 特定并行性和工作负载下的IOPS. 显然RAM可能比磁盘慢,例如单个c ...

  8. ClickHouse表引擎详解

    ClickHouse 表引擎 ClickHouse 的表引擎是 ClickHouse 服务的核心,它们决定了 ClickHouse 的以下行为: 1.数据的存储方式和位置. 2.支持哪些查询操作以及如 ...

  9. ClickHouse表引擎之Integration系列

    ​ Integration系统表引擎主要用于将外部数据导入到ClickHouse中,或者在ClickHouse中直接操作外部数据源. 1 Kafka 1.1 Kafka引擎 ​ 将Kafka Topi ...

最新文章

  1. 为什么可以说Java语言是准动态语言?
  2. Docker镜像的分层和镜像的创建(Dockerfile)
  3. 了不起的华人女数学家们
  4. 下列哪个适合做链栈_外贸企业如何做Google推广?自然排名和付费广告哪个更适合你?...
  5. duilib CTileLayoutUI 控件
  6. 第四届中国软件工程大会征文通知
  7. wtforms Form实例化流程(源码解析)
  8. 2017-2018-1 20179215 《从问题到程序》第三章
  9. tomcat下载安装步骤(超详细)
  10. win10无线投屏_win8/win10笔记本无线投影到电视
  11. 2016 hitb-facebook-ctf capture-mexico-tls RSA-CRT-Attack
  12. git deamon 一个简单的git服务器
  13. 视频数据丢失怎么办 怎样找回丢失的视频数据
  14. html游戏代码20行,js贪吃蛇源代码 20行js代码实现的贪吃蛇大战?
  15. java候选码计算的替换法_数据库闭包和候选码求解方法
  16. chrome打开html文件显示不全,谷歌浏览器显示不全怎么办_chrome浏览器打开的网页显示不完整如何解决-win7之家...
  17. Windows 11 下 Virtualbox 6.1.34 出现 End kernel panic - not syncing: attempted to kill the idle task
  18. 网络发现自动关闭不能启用、无法启用文件和打印共享的解决办法
  19. ubuntu 12.04 给四个工作区设置不同壁纸
  20. Java 面试的“完美圣经”,有了这些还愁面试吗?

热门文章

  1. 动态dp模板题(树剖+dp+线段树)
  2. 洛谷 P2596 [ZJOI2006]书架 解题报告
  3. 使用栈实现中缀表达式转为后缀表达式和后缀表达式的求解
  4. 02-合并frame
  5. Centos或者Redhet开通telnet
  6. 屏蔽非法路由,好好上网!
  7. 浅谈“三层结构”原理与用意(转帖)
  8. 基于UDP高性能传输协议UDT
  9. Intent传递数据时,可以传递哪些类型数据
  10. 给年薪不到48w的程序员提个醒!!