clickhouse系列文章目录
第一章 clickhouse的表引擎文章目录
前言
了解表引擎的作用
表引擎(即表的类型)决定了
- 数据的存储方式和位置,写到哪里以及从哪里读取数据
- 支持哪些查询以及如何支持
- 并发数据访问
- 索引的使用(如果存在)
- 是否可以执行多线程请求
- 数据复制参数
一、表引擎的种类
TinyLog
创建表用TinyLog
hadoop102 :) create table stu1(id Int8,name String)engine=TinyLog
CREATE TABLE stu1
(
`id` Int8,
`name` String
)
ENGINE = TinyLog
Ok
0 rows in set. Elapsed: 0.003 sec.
查看表
#可以看出数据是列式的存放在文件中
[root@hadoop102 stu1]# ll
总用量 12
-rw-r----- 1 clickhouse clickhouse 27 11月 30 10:34 id.bin
-rw-r----- 1 clickhouse clickhouse 35 11月 30 10:34 name.bin
-rw-r----- 1 clickhouse clickhouse 64 11月 30 10:34 sizes.json
#通过查看sizes.json 文件,能看出文件的存储大小
[root@hadoop102 stu1]# cat sizes.json
{"yandex":{"id%2Ebin":{"size":"27"},"name%2Ebin":{"size":"35"}}}[root@hadoop102 stu1]#
#id.bin和name.bin文件查看乱码
Merge
作用
Merge 引擎 (不要跟 MergeTree 引擎混淆) 本身不存储数据,但可用于同时从任意多个其他的表中读取数据。
读是自动并行的,不支持写入。读取时,那些被真正读取到数据的表的索引(如果有的话)会被使用。
创建表
CREATE TABLE WatchLog_old(date Date, UserId Int64, EventType String, Cnt UInt64)ENGINE=TinyLog;
INSERT INTO WatchLog_old VALUES ('2018-01-01', 1, 'hit', 3);
CREATE TABLE WatchLog_new(date Date, UserId Int64, EventType String, Cnt UInt64)ENGINE=TinyLog;
INSERT INTO WatchLog_new VALUES ('2018-01-02', 2, 'hit', 3);
CREATE TABLE WatchLog as WatchLog_old ENGINE=Merge(currentDatabase(), '^WatchLog');
SELECT * FROM WatchLog;
MergeTree
Clickhouse 中最强大的表引擎当属 MergeTree (合并树)引擎及该系列(*MergeTree)中的其他引擎。
MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不断修改(重写)已存储的数据,这种策略会高效很多。
主要特点:
- 存储的数据按主键排序。
- 这使得你能够创建一个小型的稀疏索引来加快数据检索。
- 支持数据分区,如果指定了 分区键 的话。
- 在相同数据集和相同结果集的情况下 ClickHouse 中某些带分区的操作会比普通操作更快。查询中指定了分区键时 ClickHouse 会自动截取分区数据。这也有效增加了查询性能。
- 支持数据副本。
- ReplicatedMergeTree 系列的表提供了数据副本功能。更多信息,请参阅 数据副本 一节。
- 支持数据采样。
- 需要的话,你可以给表设置一个采样方法。
创建表
用-m进入
create table mt_table(date Date,id UInt8,name String)
engine=MergeTree()
partition by date
order by (id,name)
settings index_granularity=8192;
insert into mt_table values('2019-05-01',1,'zhagndan');
insert into mt_table values('2019-06-01',2,'lisi');
insert into mt_table values('2019-05-03',3,'wangwu');
查看文件结构(多复制插入几次)
保证数据量多一点,时间长一点会自动合并
ReplacingMergeTree
该引擎和 MergeTree 的不同之处在于它会删除排序键值相同的重复项。
数据的去重只会在数据合并期间进行。合并会在后台一个不确定的时间进行,因此你无法预先作出计划。有一些数据可能仍未被处理。尽管你可以调用 OPTIMIZE 语句发起计划外的合并,但请不要依靠它,因为 OPTIMIZE 语句会引发对数据的大量读写。
因此,ReplacingMergeTree 适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。
创建表
create table rmt_table(date Date,id UInt8,name String,point UInt8)
engine=ReplacingMergeTree(point)
partition by date
order by (id,name);
insert into rmt_table values('2019-07-10',1,'a',20);
insert into rmt_table values('2019-07-10',1,'a',30);
insert into rmt_table values('2019-07-11',1,'a',20);
insert into rmt_table values('2019-07-11',1,'a',30);
insert into rmt_table values('2019-07-11',1,'a',10);
#刚插入时的结果
hadoop102 :) select * from rmt_table;
SELECT *
FROM rmt_table
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-11 │ 1 │ a │ 30 │
└────────────┴────┴──────┴───────┘
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-10 │ 1 │ a │ 30 │
└────────────┴────┴──────┴───────┘
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-10 │ 1 │ a │ 20 │
└────────────┴────┴──────┴───────┘
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-11 │ 1 │ a │ 10 │
└────────────┴────┴──────┴───────┘
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-11 │ 1 │ a │ 20 │
└────────────┴────┴──────┴───────┘
5 rows in set. Elapsed: 0.014 sec.
#时间长一点之后的结果(例如睡一个午睡后)
hadoop102 :) select * from rmt_table;
SELECT *
FROM rmt_table
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-11 │ 1 │ a │ 30 │
└────────────┴────┴──────┴───────┘
┌───────date─┬─id─┬─name─┬─point─┐
│ 2019-07-10 │ 1 │ a │ 30 │
└────────────┴────┴──────┴───────┘
2 rows in set. Elapsed: 0.009 sec.
SummingMergeTree
该引擎继承自 MergeTree。区别在于,当合并 SummingMergeTree 表的数据片段时,ClickHouse 会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值。如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度。
我们推荐将该引擎和 MergeTree 一起使用。例如,在准备做报告的时候,将完整的数据存储在 MergeTree 表中,并且使用 SummingMergeTree 来存储聚合数据。这种方法可以使你避免因为使用不正确的主键组合方式而丢失有价值的数据。
创建表
create table smt_table (date Date,name String ,sum UInt16,not_sum UInt16)
engine=SummingMergeTree(sum)
partition by date
order by (date,name);
insert into smt_table values('2019-07-10','a',1,2);
insert into smt_table values('2019-07-10','b',2,1);
insert into smt_table values('2019-07-11','b',3,9);
insert into smt_table values('2019-07-11','b',3,8);
insert into smt_table values('2019-07-11','a',3,1);
insert into smt_table values('2019-07-12','c',1,3);
#刚插入时的结果
hadoop102 :) select * from smt_table;
SELECT *
FROM smt_table
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-11 │ a │ 3 │ 1 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-11 │ b │ 3 │ 9 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-10 │ a │ 1 │ 2 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-12 │ c │ 1 │ 3 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-11 │ b │ 3 │ 8 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-10 │ b │ 2 │ 1 │
└────────────┴──────┴─────┴─────────┘
6 rows in set. Elapsed: 0.022 sec.
#时间长一点之后的结果(例如睡一个午睡后)
hadoop102 :) select * from smt_table;
SELECT *
FROM smt_table
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-12 │ c │ 1 │ 3 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-11 │ a │ 3 │ 1 │
│ 2019-07-11 │ b │ 6 │ 9 │
└────────────┴──────┴─────┴─────────┘
┌───────date─┬─name─┬─sum─┬─not_sum─┐
│ 2019-07-10 │ a │ 1 │ 2 │
│ 2019-07-10 │ b │ 2 │ 1 │
└────────────┴──────┴─────┴─────────┘
5 rows in set. Elapsed: 0.014 sec.
Distributed
创建表
#三个节点都添加
create table t(id UInt16,name String)Engine=TinyLog;
insert into t(id,name) values(1,'zhangsan');
insert into t(id,name) values(2,'lisi');
show tables;
#创建分布表(102集群)
create table dis_table(id UInt16,name String)Engine=Distributed(clickhouse_cluster,default,t,id);
select * from dis_table;
#插入字段(是通过hash来分布的)
insert into dis_table values(3,'zs');