ClickHouse的表引擎

ClickHouse的表引擎

表引擎是 ClickHouse 的一大特色。可以说, 表引擎决定了如何存储表的数据。 包括:

  • 数据的存储方式和位置,写到哪里以及从哪里读取数据。
  • 支持哪些查询以及如何支持。 并发数据访问。
  • 索引的使用(如果存在)。
  • 是否可以执行多线程请求。 数据复制参数。
  • 表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎 使用的相关参数。

特别注意:引擎的名称大小写敏感。
分类:
在这里插入图片描述

Log 系列表引擎

TinyLog 是 Log 系列引擎中功能简单、性能较低的引擎。它的存储结构由数 据文件和元数据两部分组成。其中,数据文件是按列独立存储的,也就是说每一 个列字段都对应一个文件。除此之外,TinyLog 不支持并发数据读取。

StripLog 支持并发读取数据文件,当读取数据时,ClickHouse 会使用多线程 进行读取,每个线程处理一个单独的数据块。另外,StripLog 将所有列数据存储 在同一个文件中,减少了文件的使用数量。

Log 支持并发读取数据文件,当读取数据时,ClickHouse 会使用多线程进行 读取,每个线程处理一个单独的数据块。Log 引擎会将每个列数据单独存储在一 个独立文件中。

TinyLog

该引擎适用于一次写入,多次读取的场景。对于处理小批数据的中间表可以 使用该引擎。值得注意的是,使用大量的小表存储数据,性能会很低。

CREATE TABLE emp_tinylog ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点',
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )
ENGINE=TinyLog();

INSERT INTO emp_tinylog
 VALUES (1,'tom','上海',25,'技术部',20000),
 (2,'jack','上海',26,'人事部',10000); 
 
INSERT INTO emp_tinylog 
VALUES (3,'bob',' 北 京 ',33,' 财 务 部 ',50000),
(4,'tony',' 杭 州 ',28,' 销 售 事 部 ',50000);
StripLog

相比 TinyLog 而言,StripeLog 拥有更高的查询性能(拥有.mrk 标记文件,支 持并行查询),同时其使用了更少的文件描述符(所有数据使用同一个文件保存)

CREATE TABLE emp_stripelog ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )
ENGINE=StripeLog;

INSERT INTO emp_stripelog 
VALUES (1,'tom','上海',25,'技术部',20000),
(2,'jack','上海',26,'人事部',10000); 

INSERT INTO emp_stripelog 
VALUES (3,'bob',' 北 京 ',33,' 财 务 部 ',50000),
(4,'tony',' 杭 州 ',28,' 销 售 事 部 ',50000);
Log

Log 引擎表适用于临时数据,一次性写入、测试场景。Log 引擎结合了 TinyLog 表引擎和 StripeLog 表引擎的长处,是 Log 系列引擎中性能最高的表引擎。

CREATE TABLE emp_( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )
ENGINE=Log; 

INSERT INTO emp_log 
VALUES (1,'tom','上海',25,'技术部',20000),
(2,'jack','上海',26,'人事部',10000); 

INSERT INTO emp_log 
VALUES (3,'bob',' 北 京 ',33,' 财 务 部 ',50000),
(4,'tony',' 杭 州 ',28,' 销 售 事 部 ',50000);

MergeTree 系列表引擎 ♥♥

在所有的表引擎中,最为核心的当属 MergeTree 系列表引擎,这些表引擎拥 有最为强大的性能和最广泛的使用场合。对于非 MergeTree 系列的其他引擎而 言,主要用于特殊用途,场景相对有限。而 MergeTree 系列表引擎是官方主推的 存储引擎,支持几乎所有 ClickHouse 核心功能。

MergeTree

MergeTree 在写入一批数据时,数据总会以数据片段的形式写入磁盘,且数 据片段不可修改。为了避免片段过多,ClickHouse 会通过后台线程,定期合并这 些数据片段,属于相同分区的数据片段会被合成一个新的片段。这种数据片段往 复合并的特点,也正是合并树名称的由来。
特点:

  • 需要指定主键,数据按照主键排序。
  • 可以使用分区,可以通过 PARTITION KEY 语句指定分区字段,开发中一般按 月进行分区。
  • 支持数据副本,保证安全性。
  • 支持数据采样。
CREATE TABLE emp_mergetree ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )
ENGINE=MergeTree() 
ORDER BY emp_id
PARTITION BY work_place ;
  • 相同分区的数据不会马上合并,而是经过一段时间以后会自动合并。
  • 如果没有指定主键,会使用order by字段当成主键,并且主键没有唯一约束性
  • 它的功能是为了提高查询效率。
ReplacingMergeTree

MergeTree 表引擎无法对相同主键的数据进行去重,ClickHouse 提供了 ReplacingMergeTree 引擎,可以针对相同主键的数据进行去重,它能够在合并分 区时删除重复的数据。值得注意的是,ReplacingMergeTree 只是在一定程度上解 决了数据重复问题,但是并不能完全保障数据不重复。

CREATE TABLE emp_replacingmergetree (
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )
ENGINE=ReplacingMergeTree() 
ORDER BY (emp_id,name) 
PRIMARY KEY emp_id 
PARTITION BY work_place ;

手动触发合并操作:
optimize table emp_replacingmergetree final;
  • 在合并分区的数据,会基于order by字段对相同分区内的数据去重,而不是主键字段。
SummingMergeTree

该引擎继承自 MergeTree。区别在于,当合并 SummingMergeTree 表的数 据片段时,ClickHouse 会把所有具有相同主键的行合并为一行,该行包含了被合 并的行中具有数值数据类型的列的汇总值。即如果存在重复的数据,会对对这些 重复的数据进行合并成一条数据,类似于 group by 的效果。 如果用户只需要查询数据的汇总结果,不关心明细数据,并且数据的汇总条 件是预先明确的,即 GROUP BY 的分组字段是确定的,可以使用该表引擎。

CREATE TABLE emp_summingmergetree ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )ENGINE=SummingMergeTree(salary) 
ORDER BY (emp_id,name) -- 注意排序 key 是两个字段 
PRIMARY KEY emp_id -- 主键是一个字段 
PARTITION BY work_place;
  • 在合并分区的数据,会基于order by字段对相同分区内的数据对指定的列做求和操作。
Aggregatingmergetree

该表引擎继承自 MergeTree,可以使用 AggregatingMergeTree 表来做增量数 据统计聚合。如果要按一组规则来合并减少行数,则使用 AggregatingMergeTree 是合适的。AggregatingMergeTree 是通过预先定义的聚合函数计算数据并通过二 进制的格式存入表内。 与 SummingMergeTree 的区别在于:SummingMergeTree 对非主键列进行 sum 聚合,而 AggregatingMergeTree 则可以指定各种聚合函数。

CREATE TABLE emp_aggregatingmergeTree ( 
emp_id UInt16 COMMENT '员工 id',
 name String COMMENT '员工姓名', 
 work_place String COMMENT '工作地点', 
 age UInt8 COMMENT '员工年龄', 
 depart String COMMENT '部门', 
 salary AggregateFunction(sum,Decimal32(2)) COMMENT '工资' )
 ENGINE=AggregatingMergeTree()
  ORDER BY (emp_id,name) -- 注意排序 key 是两个字段
  PRIMARY KEY emp_id -- 主键是一个字段 
  PARTITION BY work_place ;

# 需要使用 INSERT…SELECT 语句进行数据插入 
INSERT INTO TABLE emp_aggregatingmergeTree 
SELECT 1,'tom','上海',25,'信息部',sumState(toDecimal32(10000,2)); 

INSERT INTO TABLE emp_aggregatingmergeTree 
SELECT 1,'tom','上海',25,'信息部',sumState(toDecimal32(20000,2));

# 查询 
SELECT emp_id, name , sumMerge(salary) 
FROM emp_aggregatingmergeTree 
GROUP BY emp_id,name;
  • 在合并分区的数据,会基于order by字段对相同分区内的数据对指定的列做聚合操作
  • 写入数据的时候通过****State声明一个求和状态
  • 查询数据的时候***Merge(salary) 进行聚合

AggregatingMergeTree 通常作为物化视图的表引擎,与普通 MergeTree 搭配 使用。

# 创建一个 MereTree 引擎的明细表 
# 用于存储全量的明细数据
# 对外提供实时查询 
CREATE TABLE emp_mergetree_base ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' )
ENGINE=MergeTree() 
ORDER BY (emp_id,name) 
PARTITION BY work_place ;

# 创建一张物化视图 
# 使用 AggregatingMergeTree 表引擎 
CREATE MATERIALIZED VIEW view_emp_agg 
ENGINE = AggregatingMergeTree() 
PARTITION BY emp_id 
ORDER BY (emp_id,name) 
AS SELECT emp_id, name, sumState(salary) AS salary 
FROM emp_mergetree_base 
GROUP BY emp_id,name;

# 向基础明细表 emp_mergetree_base 插入数据 
INSERT INTO emp_mergetree_base 
VALUES (1,'tom','上海',25,'技术部',20000),
(1,'tom','上海',26,'人事部',10000);

# 查询物化视图 
SELECT emp_id, name , sumMerge(salary) 
FROM view_emp_agg 
GROUP BY emp_id,name;
CollapsingMergeTree

CollapsingMergeTree 就是一种通过以增代删的思路,支持行级数据修改和删 除的表引擎。它通过定义一个 sign 标记位字段,记录数据行的状态。如果 sign 标记为 1,则表示这是一行有效的数据;如果 sign 标记为-1,则表示这行数据需 要被删除。当 CollapsingMergeTree 分区合并时,同一数据分区内,sign 标记为 1 和-1 的一组数据会被抵消删除。

每次需要新增数据时,写入一行 sign 标记为 1 的数据;需要删除数据时, 则写入一行 sign 标记为-1 的数据。

CREATE TABLE emp_collapsingmergetree ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名',
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资', 
sign Int8 )
ENGINE=CollapsingMergeTree(sign) 
ORDER BY (emp_id,name) 
PARTITION BY work_place ;

CollapsingMergeTree同样是以ORDER BY 排序键作为判断数据唯一性的依据。 
# 插入新增数据,sign=1 表示正常数据 
INSERT INTO emp_collapsingmergetree 
VALUES (1,'tom','上海',25,'技术部',20000,1); 
# 首先插入一条与原来相同的数据(ORDER BY 字段一致),并将 sign 置为-1 
INSERT INTO emp_collapsingmergetree 
VALUES (1,'tom','上海',25,'技术部',20000,-1); 
# 再插入更新之后的数据 
INSERT INTO emp_collapsingmergetree 
VALUES (1,'tom','上海',25,'技术部',30000,1);

# 执行分区合并操作 
optimize table emp_collapsingmergetree;
  • 通过定义标记为对相同order by字段的数据,进行删除。传入的时候,必须要先传1,再传-1,才会被删除。
VersionedCollapsingMergeTree

上面提到 CollapsingMergeTree 表引擎对于数据写入乱序的情况下,不能够实 现 数 据 折 叠 的 效 果 。 VersionedCollapsingMergeTree 表 引 擎 的 作 用 与 CollapsingMergeTree 完 全 相 同 , 它 们 的 不 同 之 处 在 于 , VersionedCollapsingMergeTree 对数据的写入顺序没有要求,在同一个分区内,任 意顺序的数据都能够完成折叠操作。 VersionedCollapsingMergeTree 使用 version 列来实现乱序情况下的数据折叠。

CREATE TABLE emp_versioned ( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资', 
sign Int8, version Int8 )ENGINE=VersionedCollapsingMergeTree(sign, version) 
ORDER BY (emp_id,name) 
PARTITION BY work_place ;

# 先插入需要被删除的数据,即 sign=-1 的数据 
INSERT INTO emp_versioned 
VALUES (1,'tom','上海',25,'技术部',20000,-1,1); 
# 再插入 sign=1 的数据 
INSERT INTO emp_versioned 
VALUES (1,'tom','上海',25,'技术部',20000,1,1);
# 在插入一个新版本数据 
INSERT INTO emp_versioned 
VALUES (1,'tom','上海',25,'技术部',30000,1,2);

# 手动合并 
optimize table emp_versioned;

虽然在插入数据乱序的情况下,依然能够实现折叠的效果。之所以能够达到 这种效果,是因为在定义 version 字段之后,VersionedCollapsingMergeTree 会自 动将 version 作为排序条件并增加到 ORDER BY 的末端,就上述的例子而言,最终 的排序字段为 ORDER BY emp_id,name,version desc。

外部集成表引擎

ClickHouse 提供了许多与外部系统集成的方法,包括一些表引擎。这些表引 擎与其他类型的表引擎类似,可以用于将外部数据导入到 ClickHouse 中,或者在 ClickHouse 中直接操作外部数据源。

  • JDBC:通过指定 jdbc 连接读取数据源;
  • MySQL:将 MySQL 作为数据存储,直接查询其数据;
  • HDFS:直接读取 HDFS 上的特定格式的数据文件;
  • Kafka:将 Kafka 数据导入 ClickHouse。
HDFS
CREATE TABLE hdfs_engine_table( 
emp_id UInt16 COMMENT '员工 id', 
name String COMMENT '员工姓名', 
work_place String COMMENT '工作地点', 
age UInt8 COMMENT '员工年龄', 
depart String COMMENT '部门', 
salary Decimal32(2) COMMENT '工资' ) ENGINE=HDFS('hdfs://master:9000/ch/hdfs_engine_table', 'CSV');
MySQL
CREATE TABLE mysql_engine_table( 
id Int32, 
name String ) 
ENGINE = MySQL( 
'master:3306',
'test', 
'student', 
'root', 
'123456');
Kafka
CREATE TABLE kafka_table ( 
uid UInt64, 
phone UInt64, 
addr String ) 
ENGINE = Kafka() 
SETTINGS 
kafka_broker_list = 'master:9092', 
kafka_topic_list = 'ck_topic', 
kafka_group_name = 'group1', 
kafka_format = 'JSONEachRow' ;

当我们一旦查询完毕之后,ClickHouse 会删除表内的数据,其实 Kafka 表引 擎只是一个数据管道,我们可以通过物化视图的方式访问 Kafka 中的数据。 1.首先创建一张 Kafka 表引擎的表,用于从 Kafka 中读取数据;
2.然后再创建一张普通表引擎的表,比如 MergeTree,面向终端用户使用;
3.最后创建物化视图,用于将 Kafka 引擎表实时同步到终端用户所使用的表中。

# 创建 Kafka 引擎表 
CREATE TABLE kafka_table_consumer ( 
uid UInt64, 
phone UInt64, 
addr String )
 ENGINE = Kafka() 
 SETTINGS 
 kafka_broker_list = 'master:9092', 
 kafka_topic_list = 'ck_topic', 
 kafka_group_name = 'group1', 
 kafka_format = 'JSONEachRow' ;


# 创建一张终端用户使用的表 
CREATE TABLE kafka_table_mergetree ( 
uid UInt64, 
phone UInt64,
addr String )
ENGINE=MergeTree() 
ORDER BY uid ;

# 创建物化视图,同步数据 
CREATE MATERIALIZED VIEW consumer TO kafka_table_mergetree 
AS SELECT uid,phone,addr FROM kafka_table_consumer ;

# 查询,多次查询,已经被查询的数据依然会被输出 
select * from kafka_table_mergetree;
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值