官网:https://clickhouse.tech/docs/zh/
二级索引:
https://www.alibabacloud.com/blog/secondary-index-in-alibaba-cloud-clickhouse-best-practices_597894
ClickHouse 是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),使用C++语言编写,主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。
特点
OLAP场景的关键特征
1.大多数是读请求
2.数据总是以相当大的批(> 1000 rows)进行写入
3.不修改已添加的数据
4.每次查询都从数据库中读取大量的行,但是同时又仅需要少量的列
5.宽表,即每个表包含着大量的列
6.较少的查询(通常每台服务器每秒数百个查询或更少)
7.对于简单查询,允许延迟大约50毫秒
8.列中的数据相对较小: 数字和短字符串(例如,每个URL 60个字节)
9.处理单个查询时需要高吞吐量(每个服务器每秒高达数十亿行)
10.事务不是必须的
11.对数据一致性要求低
12.每一个查询除了一个大表外都很小
13.查询结果明显小于源数据,换句话说,数据被过滤或聚合后能够被盛放在单台服务器的内存中
OLAP :ClickHouse
基于LSM Tree的结构 ------------数据写入后定期在后台Compaction
-----数据采取列式存储的方式,支持标准的sql查询
-----在后台compaction时也是多个段merge sort后顺序写回磁盘。
分为三种模式
本地模式
高可用模式
集群模式
数据分区与分区并行
ClickHouse将数据划分为多个partition,每个partition再进一步划分为多个index granularity(粒度),然后通过多个CPU核心分别处理其中的一部分来实现并行数据处理。
在这种设计下,单条Query就能利用整机所有CPU。极致的并行处理能力,极大的降低了查询延时。
但是有一个弊端就是对于单条查询使用多cpu,就不利于同时并发多条查询。所以对于高qps的查询业务,clickhouse并不是强项。
缺点或者限制:
- 没有完整的事务支持。
- 缺少高频率,低延迟的修改或删除已存在数据的能力。仅能用于批量删除或修改数据,但这符合 GDPR。
- 稀疏索引使得ClickHouse不适合通过其键检索单行的点查询。
数据类型
https://clickhouse.tech/docs/en/sql-reference/data-types/
特殊的几种类型:
Uint Ranges
UInt8 - [0 : 255] UInt16 - [0 : 65535] UInt32 - [0 : 4294967295] UInt64 - [0 : 18446744073709551615] 注意: 这些类型的是严格区分大小写的
没有单独的Boolean类型:使用 UInt8 类型,取值限制为 0 或 1
1.String 字符串可以任意长度的。它可以包含任意的字节集,包含空字节。 2.Fixedstring(N) 固定长度 N 的字符串,N 必须是严格的正自然数。当服务端读取长度小于 N 的字符串时候,通过在字符串末尾添加空字节来达到 N 字节长度。 当服务端读取长度大于 N 的字符串时候,将返回错误消息。 与String相比,极少会使用FixedString,因为使用起来不是很方便。
枚举类型:
包括 Enum8 和 Enum16 类型。Enum 保存 'string'= integer 的对应关系。 Enum8 用 'String'= Int8 对描述。 Enum16 用 'String'= Int16 对描述 建表 CREATE TABLE t_enum ( `x` Enum('hello' = 1, 'world' = 2) ) ENGINE = TinyLog 插入数据 INSERT INTO t_enum VALUES ('hello'), ('world'), ('hello') // ok INSERT INTO t_enum values('a') // error Unknown element'a' for type
时间类型:
目前clickhouse 有三种时间类型 1.Date 接受 年-月-日 的字符串比如 ‘2019-12-16’ 2.Datetime 接受 年-月-日 时:分:秒 的字符串比如 ‘2019-12-16 20:50:10’ Datetime64 接受 年-月-日 时:分:秒.亚秒 的字符串比如 ‘2019-12-16 20:50:10.66
数组:两种形式:Array(),[ ] ;不支持多维数组
常用引擎:
Memory:内存引擎:简单查询速度快(极限测试10G/s),没有持久化;重启后数据丢失;主要用于数据量不大的情况下进行缓存和计算(1亿行)
Tingloy:以列文件的形式保存在磁盘上,不支持索引,没有并发控制。一般保存少量数据的小表,生产环境上作用有限。可以用于平时****练习测试****用。
MergeTree:合并树 最常用引擎;一般带有Partition、 Primary Key、order by三个关键字段参数
create table t_order_mt( id UInt32, sku_id String, total_amount Decimal(16,2) TTL create_time+interval 10 SECOND,----针对某列过期,参照列必须为date或者DateTime类型的 create_time Datetime ) engine=MergeTree partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id)
Partition by:分区的目的主要是降低扫描的范围,优化查询速度。如果不填: 只会使用一个分区。
—设置分区后操作以分区为基本单位进行扫描处理;可以实现提高并行度,减少全表扫描;
–分区不是立即写入的!需要合并时一同进入分区;
[^Optimize table xx final]:
Primary Key: clickhouse中的主键,和其他数据库不太一样,它只提供了数据的一级索引,但是却****不是唯一约束****。这就意味着是可以存在相同primary key的数据的。
----主要作用是建立稀疏索引----稀疏索引的好处就是可以用很少的索引数据,定位更多的数据,代价就是只能定位到索引粒度的第一行,然后再进行进行一点扫描。理论上可以完全加载到内存中, 从提高查询速度
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78RgpymU-1660201961509)(E:\BIG DATA\知识总结\数仓\online\pic\稀疏索引.png)]
order by:order by 设定了分区内的数据按照哪些字段顺序进行有序保存。—唯一必填项
----字段必须有主键作为前置字段
TTL :过期时间–当一列所有的数据都过期会删除此列数据
alter table t_order_mt3 MODIFY TTL create_time + INTERVAL 10 SECOND;
—表级的过期时间单位
- SECOND - MINUTE - HOUR - DAY - WEEK - MONTH - QUARTER - YEAR
ReplacingMergeTree[ver]:去重的合并数;自带分区内去重
----自动去重;分区内在后台合适实际进行去重;
----可以强制执行;
----去重条件为order by字段相同
----ver:版本–以版本字段较大的来进行数据的保留
SummingMergeTree:求和合并树 自带预聚合功能;
代码:
create table t_order_smt( id UInt32, sku_id String, total_amount Decimal(16,2) , create_time Datetime ) engine =SummingMergeTree(total_amount) partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id )
整理:
\1. 以SummingMergeTree(字段)中指定的列作为汇总数据列。可以填写多列必须数字列,如果不填,以所有非维度列且为数字列的字段为汇总数据列\
\2. 以order by 的列为准,作为维度列(group by …)
\3. 其他的列保留第一行。
\4. 不在一个分区的数据不会被预聚合。
\5. 聚合发生的时机不确定
\6. 查询的时候仍然需要sql聚合语句
ReplicatedMergeTree:副本合并数 高可用使用
常用操作
插入操作:
insert values
INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ...
insert select
INSERT INTO [db.]table [(c1, c2, c3)] SELECT ...
更新与删除:
删除:alter table t_order_smt delete where sku_id =‘sku_001’;
修改 :
alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id =102;
由于Mutation语句是一种很“重”的操作,而且不支持事务,Mutation语句分两步执行,同步执行的部分其实只是进行新增数据新增分区和并把旧分区打上逻辑上的失效标记。直到触发分区合并的时候,才会删除旧数据释放磁盘空间。
特殊groupby操作
with rollup:2.从右至左去掉维度进行小计
with cube: 各种维度组合进行聚合
with taotals: 仅仅多了一个总计
修改表结构—尽量不要用
--同mysql的修改字段基本一致
--新增字段
alter table tableName add column newcolname String after col1;
--修改字段类型
alter table tableName modify column newcolname String ;
--删除字段
alter table tableName drop column newcolname ;
❤!!!冗余字段:一般在设计时会在满足需求的条件时多预留几个字段,作为冗余字段;(按经验而定)
数据导出:
clickhouse-client --query "select toHour(create_time) hr ,count(*) from test1.order_wide where dt='2020-06-23' group by hr" --format CSVWithNames> ~/rs1.csv #JSON代表json
输出格式:https://clickhouse.tech/docs/zh/interfaces/formats/#json
高可用配置
–完全依赖Zookeeper进行数据的监控;用于通知副本server状态的变更
–副本为表级别的;而不是服务器级别的;部分语句会自动产生副本;有的语句不会自动产生副本
对于 INSERT 和 ALTER 语句操作数据会在压缩的情况下被复制
而 CREATE,DROP,ATTACH,DETACH 和 RENAME 语句只会在单个服务器上执行,不会被复制
因此要实现高可用除了配置两台机外还需要两个broker建立相同的表
create table rep_t_order_mt2020 ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/tables/01/rep_t_order_mt2020','rep_hadoop102') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-501hJ5RR-1660201961510)(E:\BIG DATA\知识总结\数仓\online\pic\HA.png)]
高并发的计算与使用
高可用仅仅是做到了数据的备份;并没有增加框架的数据存储量
使用高并发可以通过Distributed表引擎 把一份完整的数据进行切分,不同的分片分布到不同的节点上;
类似于MyCat之于MySql,成为一种中间件,通过分布式逻辑表来写入、分发、路由来操作多台节点不同分片的分布式数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jEiAS3VO-1660201961510)(E:\BIG DATA\知识总结\数仓\online\pic\读写原理1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChS4ewss-1660201961511)(E:\BIG DATA\知识总结\数仓\online\pic\读写原理2)]
集群的规划:------------即分片, 又复本的集群.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cyewqnNj-1660201961511)(E:\BIG DATA\知识总结\数仓\online\pic\集群规划)]
修改配置文件:
在hadoop102, 打开配置文件:
sudo vim /etc/clickhouse-server/config.d/metrika.xml
<?xml version="1.0"?>
<yandex>
<clickhouse_remote_servers>
<gmall_cluster> <!-- 集群名称-->
<shard> <!--集群的第一个分片-->
<internal_replication>true</internal_replication>
<replica> <!-- 该分片的第一个副本 -->
<host>hadoop102</host>
<port>9000</port>
</replica>
<replica> <!-- 该分片的第二个副本-->
<host>hadoop103</host>
<port>9000</port>
</replica>
</shard>
<shard> <!--集群的第二个分片-->
<internal_replication>true</internal_replication>
<replica> <!-- 该分片的第一个副本-->
<host>hadoop104</host>
<port>9000</port>
</replica>
</shard>
</gmall_cluster>
</clickhouse_remote_servers>
<zookeeper-servers>
<node index="1">
<host>hadoop102</host>
<port>2181</port>
</node>
<node index="2">
<host>hadoop103</host>
<port>2181</port>
</node>
<node index="3">
<host>hadoop104</host>
<port>2181</port>
</node>
</zookeeper-servers>
<!-- 宏: 将来建表的时候, 可以从这里自动读取, 每个机器上的建表语句就可以一样了 相当于变量 -->
<macros>
<shard>01</shard> <!-- 不同机器放的分片索引不一样, hadoop103,hadoop104需要更改 -->
<replica>hadoop102</replica> <!-- 不同机器放的副本数不一样, hadoop103,hadoop104需要更改, 以主机命名比较方便-->
</macros>
</yandex>
sudo vim /etc/clickhouse-server/config.xml
找到<zookeeper>节点, 在下面添加如下内容
<include_from>/etc/clickhouse-server/config.d/metrika.xml</include_from>
分发,更改优化本地配置;
重启服务;
分布式操作
-
三个节点创建相同的数据库 gmall
-
在一个节点创建本地表;----自动同步到三个节点
-----先切换数据库 create table st_order_mt_gmall on cluster gmall_cluster ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/tables/gmall/{shard}/st_order_mt_gmall','{replica}') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);
3.在一个节点创建分布式表;----自动同步到三个节点
create table st_order_mt_gmall_all on cluster gmall_cluster ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime )engine = Distributed(gmall_cluster,gmall, st_order_mt_gmall,hiveHash(sku_id)); ---------Distribed(集群名字,数据库名,本地表名字,数据分发根据字段)
4.向分布式表写入数据;
insert into st_order_mt_gmall_all values(201,'sku_001',1000.00,'2020-06-01 12:00:00') , (202,'sku_002',2000.00,'2020-06-01 12:00:00'), (203,'sku_004',2500.00,'2020-06-01 12:00:00'), (204,'sku_002',2000.00,'2020-06-01 12:00:00') (205,'sku_003',600.00,'2020-06-02 12:00:00')