clickhouse表引擎

clickhouse表引擎

  • clickhouse表引擎
  • TinyLog
  • Memory
  • Merge
  • MergeTree
  • ReplacingMergeTree
  • SummingMergeTree
  • Distributed

clickhouse表引擎

表引擎(即表的类型)决定了:

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

clickhouse的表引擎有很多,下面介绍其中几种,对其他引擎有兴趣的可以去查阅官方文档.

TinyLog

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

该引擎没有并发控制:

  • 如果同时从表中读取和写入数据,则读取操作将抛出异常;
  • 如果同时写入多个查询中的表,则数据将被破坏.

这种表引擎的典型用法是write-once:首先只写入一次数据,然后根据需要多次读取.此引擎适用于相对较小的表(建议最多100万行).如果有许多小表,则使用此表引擎是适合的,因为它比需要打开的文件更少.当拥有大量小表时,可能会导致性能低下.不支持索引.

例子:创建一个TinyLog引擎的表并插入一条数据

create table t(a UInt16,b String) ENGINE=TinyLog;
insert into t (a,b) values(1,'abc');

此时我们到保存数据的目录 /var/lib/clickhouse/data/default/t 中可以看到如下目录结构:

[root@hadoop102 t]# ls
a.bin  b.bin  sizes.json

a.bin 和 b.bin 是压缩过的对应的列的数据,sizes.json中记录了每个*.bin文件的大小:

[root@hadoop102 t]# cat sizes.json
{"yandex":{"a%2Ebin":{"size":"28"},"b%2Ebin":{"size":"30"}}}

Memory

内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失.读写操作不会相互阻塞,不支持索引.简单查询下有非常非常高的性能表现(超过10G/s).

一般用到它的地方不多,除了用来测试,就是在需要非常高的性能,同时数据量又不太大(上限大概1亿行)的场景.

Merge

Merge引擎(不要跟MergeTree引擎混淆)本身不存储数据,但可用于同时从任意多个其他的表中读取数据.读是自动并行的,不支持写入.读取时,那些被真正读取到数据的表的索引(如果有的话)会被使用.

Merge引擎的参数:一个数据库名和一个用于匹配表名的正则表达式.

例子:先建t1,t2,t3三个表,然后用Merge引擎的 t 表再把它们连接起来.

create table t1(id UInt16,name String) ENGINE=TinyLog;
create table t2(id UInt16,name String) ENGINE=TinyLog;
create table t3(id UInt16,name String) ENGINE=TinyLog;

insert into t1(id,name) values(1,'first');
insert into t2(id,name) values(2,'second');
insert into t3(id,name) values(3,'three');

create table t (id UInt16,name String) ENGINE=Merge(currentDatabase(),'^t');

select * from t;
┌─ id ─┬─name────┐
│  1first │
└──────┴─────────┴
┌─ id ─┬─name────┐
│  3   │   three │
└──────┴─────────┴
┌─ id ─┬─name────┐
│  2second │
└──────┴─────────┴

MergeTree

clickhouse中最强大的表引擎当属MergeTree(合并树)引擎及该系列中的其他引擎.

MergeTree引擎系列的基本理念是当你有巨量数据要插入到表中,你要搞笑地一批批写入数据片段,并希望这些数据片段在后台按照一定规则合并.相比在插入时不断修改(重写)数据进存储,这种策略会高效很多.

格式:

ENGINE [=] MergeTree(data-column [,sampling_expression],(primary,key),index_granularity)

参数解释:

data-column : 类型为date的列名.clickhouse会自动依据这个列按月创建分区.分区名格式为"YYYYMM".

sampling_expression : 采样表达式.

(primary,key) : 主键.类型为Tuple()

index_granularity : 索引粒度.即索引中相邻"标记"间的数据行数.设为8192可以适用大部分场景.

例子:

create table mt_table(date Date,id UInt8,name String) ENGINE=MergeTree(date,(id,name),8192);

insert into mt_table values('2019-05-01',1,'zhangsan');
insert into mt_table values('2019-06-01',2,'lisi');
insert into mt_table values('2019-05-03',3,'wangwu');

在/var/lib/clickhouse/data/default/mt_tree下可以看到:

[root@hadoop102 mt_table]# ls
20190501_20190501_2_2_0		20190503_20190503_6_6_0		20190601_20190601_4_4_0		detached

随便进入一个目录:
[root@hadoop102 20190601_20190601_4_4_0]# ls
checksums.txt		columns.txt		date.bin		date.mrk		id.bin		id.mark		name.bin		name.mrk		primary.idx
  • *.bin是按列保存数据的文件
  • *.mrk保存块偏移量
  • primary.idx保存主键索引

ReplacingMergeTree

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

格式:

ENGINE [=] ReplacingMergeTree(date_column [,sampling_expression],(primary,key),index_granularity,[ver])

可以看到它比MergeTree多了一个ver参数,这个ver指版本列.

例子:

create table rmt_table(date Date,id UInt8,name String,point UInt8) ENGINE=ReplacingMergeTree(date,(id,name),8192,point);

插入一些数据:
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);

等待一段时间或optimize table rmt_table 手动出发merge,后查询
select * from rmt_table;
┌───────date─┬───id───┬───name──┬─point─┐
│ 2019-07-111 │  a       │   30 │
└────────────┴────────┴───────────┴─────┘

SummingMergeTree

该引擎继承自MergeTree.区别在于,当合并SummingMergeTree表的数据片段时,clickhouse会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值.如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度,对于不可加的列,会取一个最先出现的指.

语法:

ENGINE [=] SummingMergeTree(date-column [,sampling_expreesion],(primary,key),index_granularity,[columns])

columns – 包含将要被汇总的列的列名的元组

例子:

create table smt_table(date Date,name String,a UInt16,b UInt16) ENGINE=SummingMergeTree(date,(date,name),8192,(a))

插入数据:
insert into smt_table(date,name,a,b) values('2019-07-10','a',1,2);
insert into smt_table(date,name,a,b) values('2019-07-10','b',2,1);
insert into smt_table(date,name,a,b) values('2019-07-11','b',3,8);
insert into smt_table(date,name,a,b) values('2019-07-11','b',3,8);
insert into smt_table(date,name,a,b) values('2019-07-11','a',3,1);
insert into smt_table(date,name,a,b) values('2019-07-12','c',1,3);

等待一段时间或optimize table smt_table 手动出发merge,后查询
select * from smt_table;
┌───────date─┬──name──┬───a──┬────b───┐
│ 2019-07-10 │      a │  12 │
│ 2019-07-10 │      b │  21 │
│ 2019-07-11 │      a │  31 │
│ 2019-07-11 │      b │  68 │
│ 2019-07-12 │      c │  13 │
└────────────┴────────┴─────────┴─────┘

发现2019-07-11,b的a列合并相加了,b列取了8(因为b列为8的数据最先插入.

Distributed

分布式引擎,本身不存储数据,但可以在多个服务器上进行分布式查询.读是自动并行的.读取时,远程服务器表的索引(如果有的话)会被使用.

Distributed(cluster_name,database,table [,sharding_key])

参数解析:

cluster_name - 服务器配置文件中的集群名,在/etc/metrika.xml中配置的

database - 数据库名

table - 表名

sharding_key - 数据分片键

案例演示:

  1. 在hadoop102,hadoop103,hadoop104上分别创建一个表t

    create table t(id UInt16,name String) ENGINE=TinyLog;
    
  2. 在三台机器的t表中插入一些数据

    insert into t(id,name) values(1,'zhangsan');
    insert into t(id,name) values(2,'lisi');
    
  3. 在hadoop102上创建分布式表

    create table dis_table(id UInt16,name String) ENGINE=Distributed(perftest_3shards_1replicas,default,t,id);
    
  4. 往dis_table中插入数据

    insert into dis_table select * from t;
    
  5. 查看数据量

    select count(*) from dis_table;
    
    ┌─ count(*) ─┬
    │  8   │ 
    └───────────┴
    
    select count(*) from t
    ┌─ count(*) ─┬
    │  3  │ 
    └───────────┴
    

    可以看到每个节点大约有1/3的数据.

你可能感兴趣的:(clickhouse预研)