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, \
StartDate
SELECT
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:写入数据被丢弃、读取数据为空。