网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
PS: 国内这两年大热的数字化转型,我们也看到很多的传统方向企业加入到 ClickHouse 社区使用者阵营,因为我们也能看到一些很有意思的场景,如:
- IOT 场景:一些钢铁厂用 ClickHouse 采集、监控、分析自己内部 IOT 数据。我知道的最大的集群超过 100 台了。
- 政府大数据:ClickHouse 赋能政府合作伙伴,针对政府大量结构化和非结构化数据,进行大量数据质量整理和搜索。
- 网管监控:针对一些特殊 APP、特殊网站的日志,快速分析和快速报警。
关于数字化转型,我多啰嗦两句。事实上,ClickHouse 解决的是“数据分析的最后一公里”,解决了很多数字化转型企业数据分析的效率问题,包括:
● 大数据建设完成后最终产出了大量的 BI 报表、OLAP 分析,数据驱动距离业务远。
● 有经验的业务分析人员无法快速获得需要的数据,或者需要复杂 NoSQL 技术。
● 数据驱动还是“人”驱动,还有大量的提数、出报表的需求,而很多报表往往只用一次。
● 业务快速变化要求更新速度高,数据流无法让业务人员上手。
我举例的这些都是企业在数据化升级当中遇到的问题,因为越来越多的运营、产品、决策都需要用到灵活查询的一手明细数据,过去传统的层层数据仓库,OLAP 已经不能满足这些需求了,这正是 ClickHouse 的拿手好戏。
3. 性能测评
TODO 待补充
4. 安装
系统要求:
ClickHouse可以在任何具有x86_64,AArch64或PowerPC64LE CPU架构的Linux,FreeBSD或Mac OS X上运行。
官方预构建的二进制文件通常针对x86_64进行编译,并利用SSE 4.2指令集,因此,除非另有说明,支持它的CPU使用将成为额外的系统需求。下面是检查当前CPU是否支持SSE 4.2的命令:
$ grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"
要在不支持SSE 4.2或AArch64,PowerPC64LE架构的处理器上运行ClickHouse,您应该通过适当的配置调整从源代码构建ClickHouse。
4.1 单机安装
推荐使用RPM方式安装
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo
sudo yum install -y clickhouse-server clickhouse-client
sudo /etc/init.d/clickhouse-server start
clickhouse-client # or "clickhouse-client --password" if you set up a password.
然后运行命令安装:
sudo yum install clickhouse-server clickhouse-client
启动
如果没有service,可以运行如下命令在后台启动服务:
$ sudo /etc/init.d/clickhouse-server start
日志文件将输出在/var/log/clickhouse-server/文件夹。
如果服务器没有启动,检查/etc/clickhouse-server/config.xml中的配置。
您也可以手动从控制台启动服务器:
$ clickhouse-server --config-file=/etc/clickhouse-server/config.xml
在这种情况下,日志将被打印到控制台,这在开发过程中很方便。
如果配置文件在当前目录中,则不需要指定——config-file参数。默认情况下,它的路径为./config.xml。
ClickHouse支持访问限制设置。它们位于users.xml文件(与config.xml同级目录)。 默认情况下,允许default用户从任何地方访问,不需要密码。可查看user/default/networks。 更多信息,请参见Configuration Files。
启动服务后,您可以使用命令行客户端连接到它:
$ clickhouse-client
注意: clickhouse-client 默认是单行模式,即以 “换行符” 作为语句结束的标志。所以,即使不加分号也是可以的。如果在该模式下,需要输入多行语句,可以使用 “反斜杠” 来标识该行未结束,鉴于单行模式执行多行命令太麻烦,要在每行行末都加上反斜杠,因此就有了多行模式。
命令为 clickhouse-client -m,多行命令以分号作为命令结束的标识,而非换行符。
4.2 集群安装
● 安装java
● 安装Zookeeper(依赖Java)
● 安装单机ClickHouse
● 修改ClickHouse配置为集群版
安装java; zk 自行百度
4.2.1 修改clickhouse配置为集群版
备份默认配置文件:cp /etc/clickhouse-server/config.xml /etc/clickhouse-server/config.xml.bak
然后编辑默认配置文件 /etc/clickhouse-server/config.xml 并删除集群相关的配置
- 文件中<remote_servers></remote_servers>标签里的全部内容
- 文件中标签里的全部内容
- 文件中标签里的全部内容
添加自定义配置文件:vi /etc/clickhouse-server/config.d/config.xml 内容如下
<yandex>
<zookeeper>
<node index="1">
<host>zookeeper的服务器地址</host>
<port>2181</port>
</node>
<identity>zk_username:zk_password</identity>
<session_timeout_ms>600000</session_timeout_ms>
</zookeeper>
<remote_servers>
<test>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>本机IP</host>
<port>9000</port>
<user>default</user>
<password>password</password>
</replica>
</shard>
</test>
</remote_servers>
<networks>
<ip>::/0</ip>
</networks>
<macros>
<shard>01</shard>
<replica>node1</replica>
</macros>
</yandex>
然后重启CK即可:service clickhouse-server restart
4.2.1.1 配置解读
remote_servers 配置
- a. remote_servers下级节点为集群,可配置多个集群
- b. 集群下级节点为分片(shard),可配置多个shard,不同shard不能用同一个ClickHouse实例
- c. 分片下级为副本(replica),可对分片配置多个副本,默认最少0个,不同副本不能用同一个ClickHouse实例
- d. internal_replication 用来控制当数据写入时(必须是Replicated*的表),由分片自己负责副本间的数据复制,否则分布式表的副本数据写入需要由Distributed引擎来负责
macros 配置
- a. 本质上就是针对当前实例的全局变量的定义,可以被某些地方来引用
- b. 此配置需要在集群中全局唯一
- c. 此处的参数会在创建Replicated*的表时被引用
- d. shard的值为当前节点在在集群中的分片编号,需要在集群中唯一
- e. replica是副本的唯一标识,需要在单个分片的多个副本中唯一
5. 数据类型
截至目前20220918, ck支持的数据类型如下:
数据类型的说明与案例官方文章写的非常清楚,大家以官方文章为准
https://clickhouse.com/docs/zh/sql-reference/data-types/
5.1 类型分类
ClickHouse是一款分析型数据库,有多种数据库类型,分为:
● 基础类型
● 复合类型
● 特殊类型。
其中基础类型使用ClickHouse具备了描述数据的基本能力,而另外两种类型则是ClickHouse的数据表达能力更加丰富。
5.1.1 基础类型(三种):
- 数值:正型;浮点型;定点数Decimal
- 字符串 : String; FixedString; UUID
- 时间:DateTime、DateTime64、Date
注意1:
没有Boolean类型,但可以使用整型的0或1代替。
注意2:
建议您尽可能以整数形式存储数据。例如,将固定精度的数字转换为整数值,例如货币数量或页面加载时间用毫秒为单位表示
注意: 使用浮点数计算可能会引起四舍五入的误差。
● 计算的结果取决于计算方法(计算机系统的处理器类型和体系结构)
● 浮点计算结果可能是诸如无穷大(INF)和«非数字»(NaN)。对浮点数计算的时候应该考虑到这点。
● 当一行行阅读浮点数的时候,浮点数的结果可能不是机器最近显示的数值。
注意3:
时间类型分为DateTime、DateTime64、Date。ClickHouse目前没有时间戳类型。时间类型最高的精度是秒,也就是说,如果需要毫秒、微妙等大于秒分辩率的时间,则只能借助UInt类型实现。
5.2.2 复合类型
ClickHouse还提供了数组、元祖、枚举和嵌套四类复合类型。这些类型通常是其他数据库原生不具备的特性。拥有了复合类型之后,ClickHouse的数据模型表达能力更强。
eg: Array、Tuple、Enum、Nested
5.3.3 特殊类型
- Nullable 可为空类型:
- Domain 域类型
Domain类型是特定实现的类型,它总是与某个现存的基础类型保持二进制兼容的同时添加一些额外的特性,以能够在维持磁盘数据不变的情况下使用这些额外的特性。目前ClickHouse暂不支持自定义domain类型。
IPv4是与UInt32类型保持二进制兼容的Domain类型,其用于存储IPv4地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。
IPv6是与FixedString(16)类型保持二进制兼容的Domain类型,其用于存储IPv6地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。
6. 表引擎
表引擎算是Clickhouse核心特色了,非常的灵活,ck的争议很大的来源就是引擎的设计与使用,通常我们使用数据库的习惯是拿来就用,如何存储?如何查询?如何并发?如何备份等等都是底层封装好的,但CK的表引擎设计,就像我们从自动挡时代回到了手动挡时代,是缺点但更是其优点制胜点!!!
所以想要玩好clickhouse,就必须精通表引擎这个"手动挡",才能让我们在后续的工作中一路飙车~~~
表引擎(即表的类型)决定了:
● 数据的存储方式和位置,写到哪里以及从哪里读取数据
● 支持哪些查询以及如何支持。
● 并发数据访问。
● 索引的使用(如果存在)。
● 是否可以执行多线程请求。
● 数据复制参数。
表引擎的使用方式就是必须显式在创建表时定义该表使用的引擎,以及引擎使用的相关 参数。
6.1 引擎类型分类
● MergeTree
● 日志
● 集成引擎
● 用于其他特定功能的引擎
● 虚拟列
6.2 MergeTree
ClickHouse 中最强大的表引擎当属 MergeTree(合并树)引擎及该系列(MergeTree) 中的其他引擎,支持索引和分区,地位可以相当于 innodb 之于 Mysql。而且基于 MergeTree, 还衍生除了很多小弟,也是非常有特色的引擎。
案例练习
-- DDL
create table ads_user_gift_mt(
id UInt32,
gift_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,gift_id);
-- 数据
insert into ads_user_gift_mt values
(101,'gift\_001',1000.00,'2022-09-01 12:00:00') ,
(102,'gift\_002',2000.00,'2022-09-01 11:00:00'),
(102,'gift\_004',2500.00,'2022-09-01 12:00:00'),
(102,'gift\_002',2000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',12000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',600.00,'2022-09-02 12:00:00');
MergeTree 其实还有很多参数(绝大多数用默认值即可),但是三个参数是更加重要的, 也涉及了关于 MergeTree 的很多概念。
6.2.1 partition by 分区(可选 )
作用:
学过 hive 的应该都不陌生,分区的目的主要是降低扫描的范围,优化查询速度
默认:
如果不填,则只会使用一个分区。
分区目录:
MergeTree 是以列文件+索引文件+表定义文件组成的,但是如果设定了分区那么这些文 件就会保存到不同的分区目录中。
并行:
分区后,面对涉及跨分区的查询统计,ClickHouse 会以分区为单位并行处理。
数据写入与分区合并 :
任何一个批次的数据写入都会产生一个临时分区,不会纳入任何一个已有的分区。写入 后的某个时刻(大概 10-15 分钟后),ClickHouse 会自动执行合并操作(等不及也可以手动 通过 optimize 执行),把临时分区的数据,合并到已有分区中。
optimize table xxxx final;
例子:
再次执行上面的插入操作
insert into ads_user_gift_mt values
(101,'gift\_001',1000.00,'2022-09-01 12:00:00') ,
(102,'gift\_002',2000.00,'2022-09-01 11:00:00'),
(102,'gift\_004',2500.00,'2022-09-01 12:00:00'),
(102,'gift\_002',2000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',12000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',600.00,'2022-09-02 12:00:00');
查看数据并没有纳入任何分区
手动 optimize 之后
optimize table ads_user_gift_mt final;
6.2.2 primary key 主键(可选)
ClickHouse 中的主键,和其他数据库不太一样,它只提供了数据的一级索引,但是却不 是唯一约束。这就意味着是可以存在相同 primary key 的数据的。
主键的设定主要依据是查询语句中的 where 条件。
根据条件通过对主键进行某种形式的二分查找,能够定位到对应的 index granularity,避 免了全表扫描。
index granularity: 直接翻译的话就是索引粒度,指在稀疏索引中两个相邻索引对应数 据的间隔。ClickHouse 中的 MergeTree 默认是 8192。官方不建议修改这个值,除非该列存在 大量重复值,比如在一个分区中几万行才有一个不同数据。
稀疏索引:
稀疏索引的好处就是可以用很少的索引数据,定位更多的数据,代价就是只能定位到索 引粒度的第一行,然后再进行进行一点扫描。
6.2.3 order by(必选)
order by 设定了分区内的数据按照哪些字段顺序进行有序保存。
order by 是 MergeTree 中唯一一个必填项,甚至比 primary key 还重要,因为当用户不 设置主键的情况,很多处理会依照 order by 的字段进行处理(比如后面会讲的去重和汇总)。
要求:主键必须是 order by 字段的前缀字段。
比如 order by 字段是 (id,sku_id) 那么主键必须是 id 或者(id,sku_id)
6.2.4 二级索引
当需要从表中查询千万级数据量时,如果查询时间太慢,我们可以给日志表添加二级索引;
二级索引:
主索引是在我们创建表激活后由系统自动创建的,这个不能修改;
二级索引可以自己创建。
主索引是表的主键,二级索引可以根据你自己需要用到表的任何字段的组合来创建。
目前在 ClickHouse 的官网上二级索引的功能在 v20.1.2.4 之前是被标注为实验性的,在 这个版本之后默认是开启的。
老版本使用二级索引前需要增加设置
是否允许使用实验性的二级索引(v20.1.2.4 开始,这个参数已被删除,默认开启)
set allow_experimental_data_skipping_indices=1;
创建测试表
create table ads_user_gift_mt2(
id UInt32,
gift_id String,
total_amount Decimal(16,2),
create_time Datetime,
INDEX a total_amount TYPE minmax GRANULARITY 5
) engine =MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id, gift_id);
-- 插入数据
insert into ads_user_gift_mt2 values
(101,'gift_001',1000.00,'2022-09-01 12:00:00') ,
(102,'gift_002',2000.00,'2022-09-01 11:00:00'),
(102,'gift_004',2500.00,'2022-09-01 12:00:00'),
(102,'gift_002',2000.00,'2022-09-01 13:00:00'),
(102,'gift_002',12000.00,'2022-09-01 13:00:00'),
(102,'gift_002',600.00,'2022-09-02 12:00:00');
其中 GRANULARITY N 是设定二级索引对于一级索引粒度的粒度。
对比效果
那么在使用下面语句进行测试,可以看出二级索引能够为非主键字段的查询发挥作用。
clickhouse-client --send_logs_level=trace <<< 'select \* from ads\_user\_gift\_mt2 where total\_amount > toDecimal32(900., 2)';
6.2.5 数据 TTL
TTL 即 Time To Live,MergeTree 提供了可以管理数据表或者列的生命周期的功能。
● 列级TTL (到期后指定的字段数据归0)
● 表级TTL (到期后丢失)
6.3 ReplacingMergeTree
ReplacingMergeTree 是 MergeTree 的一个变种,它存储特性完全继承 MergeTree,只是 多了一个去重的功能。 尽管 MergeTree 可以设置主键,但是 primary key 其实没有唯一约束 的功能。如果你想处理掉重复的数据,可以借助这个 ReplacingMergeTree。
6.3.1 去重时机
数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以你无法预 先作出计划。有一些数据可能仍未被处理 。
6.3.2 去重范围
如果表经过了分区,去重只会在分区内部进行去重,不能执行跨分区的去重。
所以 ReplacingMergeTree 能力有限, ReplacingMergeTree 适用于在后台清除重复的数 据以节省空间,但是它不保证没有重复的数据出现。
6.3.3 案例
create table user_gift_rmt(
id UInt32,
gift_id String,
total_amount Decimal(16,2) ,
create_time Datetime
) engine =ReplacingMergeTree(create_time)
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id, gift_id);
ReplacingMergeTree() 填入的参数为版本字段,重复数据保留版本字段值最大的。 如果不填版本字段,默认按照插入顺序保留最后一条。
insert into user_gift_rmt values
(101,'gift\_001',1000.00,'2022-09-01 12:00:00') ,
(102,'gift\_002',2000.00,'2022-09-01 11:00:00'),
(102,'gift\_004',2500.00,'2022-09-01 12:00:00'),
(102,'gift\_002',2000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',12000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',600.00,'2022-09-02 12:00:00');
6.4 SummingMergeTree
对于不查询明细,只关心以维度进行汇总聚合结果的场景。如果只使用普通的MergeTree 的话,无论是存储空间的开销,还是查询时临时聚合的开销都比较大。 ClickHouse 为了这种场景,提供了一种能够**“预聚合”**的引擎 SummingMergeTree
案例演示
create table user_gift_smt(
id UInt32,
gift_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,gift_id );
insert into user_gift_smt values
(101,'gift\_001',1000.00,'2022-09-01 12:00:00') ,
(102,'gift\_002',2000.00,'2022-09-01 11:00:00'),
(102,'gift\_004',2500.00,'2022-09-01 12:00:00'),
(102,'gift\_002',2000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',12000.00,'2022-09-01 13:00:00'),
(102,'gift\_002',600.00,'2022-09-02 12:00:00');
合并下再查: OPTIMIZE TABLE user_gift_smt FINAL;
通过结果可以得到以下结论
● 以 SummingMergeTree()中指定的列作为汇总数据列
● 可以填写多列必须数字列,如果不填,以所有非维度列且为数字列的字段为汇总数 据列
● 以 order by 的列为准,作为维度列
● 其他的列按插入顺序保留第一行
● 不在一个分区的数据不会被聚合
● 只有在同一批次插入(新版本)或分片合并时才会进行聚合
开发建议
设计聚合表的话,唯一键值、流水号可以去掉,所有字段全部是维度、度量或者时间戳。
问题
能不能直接执行以下 SQL 得到汇总值
select total_amount from XXX where province_name=’’ and create_date=’xxx’
![img](https://img-blog.csdnimg.cn/img_convert/cf49596603a50685264b643426db6af4.png)
![img](https://img-blog.csdnimg.cn/img_convert/77ab98c2bcdd2b62d2d27c6421a0ea99.png)
![img](https://img-blog.csdnimg.cn/img_convert/ca6d29a9b1237f900d43161a3829dbd9.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
填,以所有非维度列且为数字列的字段为汇总数 据列
● 以 order by 的列为准,作为维度列
● 其他的列按插入顺序保留第一行
● 不在一个分区的数据不会被聚合
● 只有在同一批次插入(新版本)或分片合并时才会进行聚合
##### 开发建议
设计聚合表的话,唯一键值、流水号可以去掉,所有字段全部是维度、度量或者时间戳。
##### 问题
能不能直接执行以下 SQL 得到汇总值
select total_amount from XXX where province_name=’’ and create_date=’xxx’
[外链图片转存中…(img-Hro7yFlI-1715471835658)]
[外链图片转存中…(img-1Fe8ZUyw-1715471835659)]
[外链图片转存中…(img-KipTO5Im-1715471835659)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新