Clickhouse

目录

Clickhouse

表引擎

库表创建&查询

建库

建表

1、 本地表与分布式表

2、创建本地表

3、 创建分布式表

常用数据类型

DDL变更

ALTER语法

数据查询

Distinct子句

From子句

Sample子句

Join子句

执行计划

实践


Clickhouse

Clickhouse是俄罗斯互联网公司Yandex开发并开源的一个用于联机分析(OLAP)的列式数据库管理系统(DBMS),使用C++语言开发。

特点(截止20.12.3.3版本):

  • 真正的面向列的数据库

  • 数据在磁盘储存,支持数据压缩

  • 分布式,支持在多个服务器上部署集群,支持分片、副本、数据复制等功能,无主从架构

  • SQL语法支持 (支持大部分标准SQL)

  • 多核并行处理,动态代码生成,向量化引擎

  • 支持实时数据摄入

  • 支持索引 (只支持主键索引,为稀疏索引[注1] )

  • 低延迟,查询响应非常快,适合不变数据 (如海量实时用户行为数据、点击日志等)在线查询

  • 支持近似预估计算,支持数据抽样[注2]

  • 支持针对账号限制查询复杂性以及配额[注3]

不完美的地方:

  • 不支持事务

  • 旧版本不支持update,delete 新版本:(异步执行,不能及时生效)

    alter table table1 update filed1 = value1, field2 = value2 where condition;

    alter table table1 delete where condition;

  • 不支持相关子查询[注4]

  • Join写法有些独特,分布式表需要加global【可通过配置文件修改成不需要加[注5] 】

  • 分片不能自动扩展,需要人为修改配置[注6]

  • 分布式不是完全自动透明的[注7]

  • UDF支持不方便[注8] (需要手动编写C++代码实现udf函数)

  • 主键不唯一,导致增量更新的困难,不方便按照主键去重/覆盖更新

注意:

使用的ck版本不支持删除操作,只能更新

表引擎

Clickhouse创建本地表的时候需要指定表引擎,类似于mysql可以选择innodb或者myisam,不同的表引擎具有不同特性,发挥不同功能,需要根据具体业务场景选择。

日常业务中使用最多的就是MergeTree系列表引擎,如下:

引擎名称 引擎说明 场景 备注
MergeTree 合并树 非去重普通场景 最基础的引擎,底层类似于LSM的方式,其他引擎都是基于其增加一些特殊特性
ReplacingMergeTree 去重合并树 需要按主键去重/覆盖更新的场合 比较通用的引擎,支持同主键去重,但是去重是后台执行,不可控(实测非常慢)
CollapsingMergeTree 折叠树 也是为了去重,方式比较独特 如果按照主键去重,需要在写入新数据时知道原来的数据方可
VersionedCollapsingMergeTree 版本折叠树 折叠树基础上加了一些优化 折叠树基础上增加了版本的概念,按版本去重
SummingMergeTree 求和合并树 相同主键的数据合并成一行并对指标自动求和 推荐结合MergeTree使用,MergeTree存放详细数据,SummmingMergeTree存储聚合数据
AggregatingMergeTree 聚集合并树 相同主键的数据合并成一行并对指标自动聚集计算 是SummingMergeTree的扩展,不局限于sum而是可以有其他聚合逻辑,常配合物化视图做增量数据的聚合

以上表引擎为单副本情况下,如果使用多副本需要使用Replicated*系列的引擎,这样可以配合zookeeper实现副本数据复制

引擎名称 说明
ReplicatedMergeTree 与对应的不带Replicated系列的功能一致,只是这种引擎支持副本数据复制
ReplicatedReplacingMergeTree
ReplicatedCollapsingMergeTree
ReplicatedVersionedCollapsingMergeTree
ReplicatedSummingMergeTree
ReplicatedAggregatingMergeTree

分布式表引擎:Distributed,用于创建分布式表

库表创建&查询

建库

--建库语法:
create database if not exists 库名
on cluster 集群名   
engine = Ordinary;  //engine就固定用这个
 
--例:
create database if not exists saas_aries
on cluster default_cluster   
engine = Ordinary;
​
--使用库:
USE saas_aries;

建表

1、 本地表与分布式表

Clickhouse中的表有本地表分布式表的概念:

本地表指各个分片节点自身的表,在各个分片节点上分别存储各自的数据,在不同的分片节点上查询本地表也只会展示当前节点上的数据;

分布式表需要关联到本地表,本身不存储数据,实际上相当于一张分布式视图,在任意节点查询分布式表,clickhouse会把计算分发到各分片节点,汇总各节点的计算结果后返回全局结果

例如:

我们有3个分片节点,有一张本地表t_data_local,共100W数据,那么节点1可能存储30W数据,节点2有20W数据,节点3有50W数据;另外有一张分布式表t_data关联到t_data_local

在节点1上查询select count(*) from t_data_local,数据量为30W;节点2上查询为20W,节点3为50W

而不管在哪个节点查询select count(*) from t_data,均为100W数据

所以查询需要查询分布式表才能获取完整的数据

Clickhouse中建表步骤分为两步:1)建立本地表;2)建立分布式表,

2、创建本地表

建议规范:分布式表使用正常的表名,本地表在后面加_local以示区分

--建表语法: 
CREATE TABLE IF NOT EXISTS 库名.本地表名 
ON CLUSTER 集群名
(
    字段1 类型 [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1], //clickhouse也支持列的ttl,过期后这一列数据删除
    字段2 类型 [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = 某引擎
ORDER BY (排序键)
[PARTITION BY expr] //分区键
[PRIMARY KEY expr] //主键,一般不设,默认跟排序键相同
[SAMPLE BY expr] //Clickhouse支持抽样
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...] //ttl,类似cassandra,clickhouse支持数据行的ttl,过期后自动删除数据
[SETTINGS name=value, ...] //一些表的设置项
​
--以ReplicatedReplacingMergeTree为例: 
create table if not exists saas_aries.dim_ec_store_localon cluster default_cluster(
    `pid` String comment '商家ID'
    ,`store_id` String comment '所属门店ID'
    ,`store_name` String comment '所属门店名称'
    ,`is_head_store` String
    ,`create_time` DateTime comment '创建时间'
)
engine = ReplicatedReplacingMergeTree(
    '/clickhouse/tables/{shard}/saas_aries/dim_ec_store_local', '{replica}'
)
order by (pid, store_id)
settings index_granularity = 8192;
3、 创建分布式表

建好本地表后,需要建立分布式表关联本地表

--建表语法(使用Distributed引擎): 
create table if not exists 库名.分布式表名on cluster 集群名as 库名.本地表名engine = Distributed(集群名, 库名, 本地表名, 分布式规则);
--例: 
create table if not exists saas_aries.dim_ec_storeon cluster default_clusteras db_test.dim_ec_store_localengine = Distributed(default_cluster, saas_aries, dim_ec_store_local, rand());
--//rand表示随机分布,也可以定义其他分布策略,如hash函数等

备注:所有的DDL语句务必都加上on cluster 集群名,这样在任意一个节点执行就相当于在集群所有节点执行,不然就需要到每个节点上依次执行一遍这个语句

常用数据类型

分类 常用类型 说明
整数 有符号整数 Int8 数据范围: -128 ~ 127
Int16 数据范围:-32768 ~ 32767
Int32 数据范围: -2147483648 ~ 2147483647
Int64 数据范围: -9223372036854775808 ~ 9223372036854775807
无符号整数 UInt8 数据范围: 0 ~ 255,clickhouse中没有0-1布尔类型,用这个类型代替
UInt16 数据范围: 0 ~ 65535
UInt32 数据范围: 0 ~ 4294967295
UInt64 数据范围: 0 ~ 18446744073709551615
浮点数 Float32 32位浮点数
Float64 64位浮点数
定点数 Decimal32(S) 32位定点数,数据范围: -1 * 10^(9-S) ~ 1 * 10^(9-S)
Decimal64(S) 64位定点数,数据范围: -1 * 10^(18-S) ~ 1 * 10^(18-S)
字符串 不定长 String 字符串,任意长度
定长 FixedString(N) 固定长度N的字符串,N为正整数
日期与时间 日期 Date 日期类型,'2021-01-08',精确到天
时间 DateTime 日期时间类型,'2021-01-08 13:13:13',精确到秒
DateTime64(precision, [timezomne]) 日期时间类型,可指定精度和时区(可选),如DateTime64(3)可表示'2021-01-08 13:13:13.222'
枚举类型 Enum8 用法:CREATE TABLE t_test_local( field1 Enum8('hello' = 1, 'world' = 2));field1字段被设置为枚举类型,它只能存储两种值'hello'与'world',插入其他值会报错误
Enum16 同Enum8,只是整数范围为Int16,一般没有必要,Enum8已足够了
特殊:Nullable Nullable(数据类型) 解释:Clickhouse中的字段类型与Mysql不同,默认来说是不允许为空的(基于性能考虑),会自动赋予个默认值如果需要允许为空的情况出现,可以用Nullable,如下所示CREATE TABLE t_test_local( field1 Nullable(Int32));表示field1字段是Int32类型,但是允许为空

DDL变更

ALTER语法

需要先在本地表操作,再在分布式表同样操作(所有的表结构变更语句都需要先在本地表执行,然后在分布式表执行,都执行完毕才可以)

ALTER TABLE 库名.表名 ON CLUSTER 集群名 ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN ...
新增字段

ALTER TABLE 库名.表名 ON CLUSTER 集群名 ADD COLUMN IF NOT EXISTS 字段名 类型 [默认值] AFTER 已存在的字段;
​
--先在本地表新增:
ALTER TABLE db_test.t_test_local ON CLUSTER default_cluster ADD COLUMN IF NOT EXISTS field5 Int32 default 0 AFTER field4;
 
--然后在分布式表新增:
ALTER TABLE db_test.t_test ON CLUSTER default_cluster ADD COLUMN IF NOT EXISTS field5 Int32 default 0 AFTER field4;
删除字段

ALTER TABLE 库名.表名 ON CLUSTER 集群名 DROP COLUMN IF EXISTS 字段名;
​
--先在本地表删除:
ALTER TABLE db_test.t_test_local ON CLUSTER default_cluster DROP COLUMN IF EXISTS field5;
 
--然后在分布式表删除:
ALTER TABLE db_test.t_test ON CLUSTER default_cluster DROP COLUMN IF EXISTS field5;
修改字段

ALTER TABLE 库名.表名 ON CLUSTER 集群名 MODIFY COLUMN IF EXISTS 字段名 类型 [默认值] [TTL]; 
--//修改字段可以修改字段的类型、字段的默认值和字段的TTL,注意:不支持修改字段名称!
​
--先在本地表修改:
ALTER TABLE db_test.t_test_local ON CLUSTER default_cluster MODITY COLUMN IF EXISTS field5 Int64 default 1;
--//把field5的类型改为Int64,默认值改为1
 
--然后在分布式表修改:
ALTER TABLE db_test.t_test ON CLUSTER default_cluster MODITY COLUMN IF EXISTS field5 Int64 default 1;
--//把field5的类型改为Int64,默认值改为1
设置注释

ALTER TABLE 库名.表名 ON CLUSTER 集群名 COMMENT COLUMN IF EXISTS 字段名 注释;
--//设置字段的注释
​
--先在本地表设置:
ALTER TABLE db_test.t_test_local ON CLUSTER default_cluster COMMENT COLUMN IF EXISTS field5 'aaa'; //把field5的注释设置为aaa
 
--然后在分布式表设置:
ALTER TABLE db_test.t_test ON CLUSTER default_cluster COMMENT COLUMN IF EXISTS field5 'aaa'; //把field5的注释设置为aaa
清空列

这里例外,这个只在本地表执行,不需要在分布式表执行:因为这个实际是操作值,而分布式表是一个结构视图,本地表的值变化了自动会反映到分布式表

ALTER TABLE 库名.表名 ON CLUSTER 集群名 CLEAR COLUMN IF EXISTS 字段名 [IN PARTITION 分区名]; 
--//清空指定列的值,in partition 可选,如果设置,只清空在改分区下的指定列的值
​
--在本地表清空:
ALTER TABLE db_test.t_test_local ON CLUSTER default_cluster CLEAR COLUMN IF EXISTS field5; 
--//把field5的值清空(会按照默认值填充,比如0或者null)

数据查询

Distinct子句

distinct 用于在结果集总去除重复项,只保留一行

如果count distinct,表示去重计数

可以使用uniq代替count distinct,为不精准去重计数,但是速度会快几倍

select count(distinct pid) from t_table1; => 结果528329 (精确)
select uniq(pid) from t_table1; => 结果528210; (基于算法,不精确)
From子句

From子句可以从表/视图/子查询/表函数中查询数据

From子句可以附带final修饰符,当 FINAL 修饰符被指定,ClickHouse会在返回结果之前完全合并数据,从而执行给定表引擎合并期间发生的所有数据转换。

select * from t_table1;  => t_table1中相同主键的记录不会合并,如果表中有重复行,会出现多条
select * from t_table1 final; =>t_table1中相同主键的记录会合并,如果表中有重复行,只会出现一条

但是,使用的查询 FINAL 执行速度会变慢很多在绝大多数情况下,避免使用 FINAL.

可选的方法是

1)首先使用ReplacingMergeTree引擎,可以后台合并相同主键记录(非即时、不可控)

2) 在系统相对空闲时间执行optimize table,手动合并

3)在应用系统处理

Sample子句

Sample子句是Clickhouse支持数据抽样功能,进行近似查询。

启用数据采样时,不会对所有数据执行查询,而只对特定部分数据(样本)执行查询。 近似查询处理在以下情况下可能很有用:

当你有严格的查询时间需求(如<100ms),但你不能通过额外的硬件资源来满足他们的成本。

当您的原始数据不准确时,所以近似不会明显降低质量。

业务需求的目标是近似结果,对准确性要求不太高。

要实现Sample抽样,首先需要在该表的建表语句中设置抽样表达式,具体查看建表相关文档。

Sample语句的语法表达式为

SAMPLE k, 其中k是一个0-1之间的小数,比如k=0.2,表示抽样20%数据来预估

--例如:select avg(cost_price) from t_table1 sample 0.2; 
--// clickhouse会抽样20%的数据样本,计算平均值来预估总体平均值

Join子句

Clickhouse 支持 inner join / left join / right join / full join / cross join

Clickhouse的分布式表Join子句,必须要在前面加上global关键字

select a.*, b.* from a left join b on a.field1 = b.field1;  --//错误
select a.*, b.* from a global left join b on a.field1 = b.field1;  --//正确

执行计划

Clickhouse数据库支持查看执行计划,具体方式为:explain + sql;

explain select * from saas_aries.dim_ec_store_local where pid = 2847 limit 100;

Dbeaver客户端软件最新版(21.0.2以上)已经可以支持查看执行计划

注意:

目前clickhouse的执行计划查询功能还不是很完善,显示的信息比较少

查看执行要查询本地表,不要查询分布式表,如果查询分布式表,目前执行计划只会给出一行信息,如下所示

《Doris实时数仓实战》

Clickhouse_第1张图片

Clickhouse_第2张图片

你可能感兴趣的:(#,数据存储工具,clickhouse,大数据)