clickhouse目前用在实时BI后台,只要数据稳定落库了,出报表很快,临时查询也很快,在使用过程中,对它的一些优点和不足也是深有体会,这里总结一下,不能做到面面俱到,但尽可能详细的介绍实际应用需要注意的问题和应用技巧。

我们是通过编写Flink程序,消费kafka数据,将数据清洗,扩充维度,然后落在clickhouse里面,半年以来,Flink程序很少出问题,数据落库也很稳定。对于clickhouse,使用的是腾讯云的clickhouse服务,有副本的集群,中间扩充了几次磁盘,服务也是挺稳定的,整体看来,整个BI后台,都能稳定的提供数据报表。为了书写方便,接下来clickhouse用ck缩写。

ck里面引用mysql外部数据表

通常需要在ck里面要用mysql里面的表,比如mysql里面存在一张维表,我们需要根据id查询出某个名称,这个时候,不需要把数据导一份过来,就可以把mysql表映射到ck里面,或者直接整个mysql数据库映射到ck某个库里面,就能操作mysql这个数据库所有表,使用sql语法关联查询mysql和ck的表。

MySQL引擎用于将远程的MySQL服务器中的表映射到ClickHouse中,并允许您对表进行INSERT和SELECT查询,以方便您在ClickHouse与MySQL之间进行数据交换。

创建数据库

CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster]
ENGINE = MySQL('host:port', ['database' | database], 'user', 'password')

比如,我们在mysql里面创建一张表:

mysql> USE test;
Database changed mysql> CREATE TABLE `mysql_table` (
-> `int_id` INT NOT NULL AUTO_INCREMENT,
-> `float` FLOAT NOT NULL,
-> PRIMARY KEY (`int_id`));
Query OK, 0 rows affected (0,09 sec) mysql> insert into mysql_table (`int_id`, `float`) VALUES (1,2);
Query OK, 1 row affected (0,00 sec) mysql> select * from mysql_table;
+------+-----+
| int_id | value |
+------+-----+
| 1 | 2 |
+------+-----+
1 row in set (0,00 sec)

我们去ck里面创建一个数据库,跟mysql这个数据库关联起来。

CREATE DATABASE mysql_db ENGINE = MySQL('localhost:3306', 'test', 'my_user', 'user_password')

这样就在ck里面创建了一个mysql_db,这个数据库跟mysql的test数据库是映射在一起了,我们在ck里面直接查询:

SELECT * FROM mysql_db.mysql_table

┌─int_id─┬─value─┐
│ 1 │ 2 │
└────────┴───────┘

数据库引擎可以是mysql,也可以是其它数据库,比如sqlite、PostgreSQL,更多可以查阅官方文档:

https://clickhouse.com/docs/zh/engines/database-engines

ck带副本的分布式表

带副本的分布式表,就是分布式表,并且单个part也是有副本的,刚开始我们建表时候,也是花了一些时间,回忆下当时的问题主要有以下:

1) 带副本的分布式表的创建问题,怎么创建?

开始我们也是创建错了,发现数据不完整,每次只有一半,后来得知腾讯云的服务是带副本的分布式集群,创建表也需要带副本的分布式表,不然数据有丢失,建表分2步,语句如下:

-- 第一步:创建本地表,这个表会在每个机器节点上面创建,不要漏了on cluster cluster_name
CREATE TABLE test.table_local on cluster default_cluster
(
`id` Int32,
`uid` String,
`name` String,
`time` Int32,
`create_at` DateTime
)
ENGINE = ReplicatedMergeTree()
PARTITION BY toYYYYMM(create_at)
ORDER BY id; -- 第二步:创建分布式表
CREATE TABLE test.table_all on cluster default_cluster as test.table_local
ENGINE = Distributed('default_cluster', 'test', 'table_local', sipHash64(id));

参数说明:

ReplicatedMergeTree:带副本的表引擎;

PARTITION BY:数据分区方式;

sipHash64(id):分布式表在每个节点上面的数据分发方式;

具体可以看官方文档,地址:

https://clickhouse.com/docs/zh/engines/table-engines/mergetree-family/replication

后文,都已这张表为例。

2)分布式表,插入数据要每个节点都执行插入操作吗?

不需要,用标准sql语法插入分布式表即可,比如:

insert into test.table_all values(.....)

3)分布式表的更新删除操作,与mysql相同吗?

不相同,只能说是相似,按照模板来使用即可,alter table语法:

ALTER TABLE [db.]table UPDATE column1 = expr1 [, ...] WHERE filter_expr

比如:

alter table test.table_local on cluster default_cluster update name = 'name' where id = 10000

注意:更新操作,需要用本地表test.table_local,不能用分布式表。

删除操作也是一样的:

alter table test.table_local on cluster default_cluster delete where id = 10000

4)分布式表,添加列,修改列的类型

-- 添加列
ALTER TABLE test.table_local ON CLUSTER default_cluster ADD COLUMN product String; -- 修改列
ALTER TABLE test.table_local on cluster default_cluster MODIFY COLUMN uid Int64;

可以看到,ck带副本的表与标准sql语法的区别在于使用了alter table和on cluster关键字,使用时候,套用模板即可。其它的一些DDL操作可以看具体官方文档:

https://clickhouse.com/docs/zh/sql-reference/statements/alter

写性能

ck提倡低频、大批量写,每秒钟只写几次,每次插入上万、十万条数据,这是比较合适的。因为如果稍微了解一下底层原理就知道,ck会间隔合并数据块,不宜频繁写入导致频繁合并,影响性能。

在使用Flink导入数据的过程中,需要攒数据,批量写,我们通过Flink窗口函数积累数据,每次写5秒钟的一批数据。记得刚开始使用ck的时候,开发没注意这些,运维就说要批量写,后来基本就统一了。

添加索引需要注意

ck里面有一级稀疏索引,和二级跳数索引,二级索引是基于一级索引的,有时候一张表建完了,写入数据,我们发现查询需要用到一些字段,需要加索引,语句:

-- 添加索引
alter table test.table_local on cluster default_cluster add index index_uid uid type minmax(100) GRANULARITY 2; -- 使索引生效,对历史数据也生效索引
ALTER TABLE test.table_local MATERIALIZE index index_uid;

也是用的alter table格式,这里需要注意的是,索引是在插入数据时候建立的,新建索引对历史数据是不生效的,需要让历史数据也生效。

数据去重

ReplacingMergeTree引擎表会删除排序键值相同的重复项,排序键值就是建表时候跟在order by后面的字段。ck对更新不友好,性能很差,于是可以利用这个引擎,每次只管写入,不需要更新,ck会自动帮我们保存最新版本。建表语句如下:

CREATE TABLE test.test_local on cluster default_cluster (
`id` UInt64,
`type` Int32,
`username` String,
`password` String,
`phone` String COMMENT '手机号账户',
`nick` String,
`mobile` String,
`insert_time` DateTime DEFAULT '2023-07-31 00:00:00'
) ENGINE = ReplicatedReplacingMergeTree()
partition by dt
order by id; CREATE TABLE test.test_all on cluster default_cluster as test.test_local ENGINE = Distributed('default_cluster', 'test', 'test_local', sipHash64(id));

insert_time字段需要有,放在最后,便于ck根据时候保留最新数据。

数据的去重只会在数据合并期间进行。合并会在后台一个不确定的时间进行,因此你无法预先作出计划。有一些数据可能仍未被处理。通常使用OPTIMIZE 语句手动触发,比如今天程序异常停止了,我启动了程序, 大概率会有多个版本数据,这个时候需要手动合并一下:

OPTIMIZE table test.test_local on cluster default_cluster final;

这样会触发数据合并,这个过程耗费性能,正常情况下,如果没有多版本数据,不需要触发合并。如果没有触发,查询数据时候,会有多个版本,需要final关键字,查询时候合并一下,如果查询很多,将非常耗费性能,这个时候可以选择定期合并。

select * from test.test_all final where id = 10000

对于这种多个版本的表,有时候也是可以避开final的,比如去重,可以select distinct id from table,而不需要select distinct id from table final,这个final是可以省的,等等。

分布式表的删除

需要删除本地表和分布式表:

drop table test.test_local on cluster default_cluster;
drop table test.test_all on cluster default_cluster;

复杂数据类型map

有些业务数据某个字段是json类型,并且key数量不定,这个时候需要将其在ck里面定义为map类型,包容性好。

CREATE TABLE test.test_local2 on cluster default_cluster (
`id` UInt64,
`data` Map(String, String),
) ENGINE = ReplicatedMergeTree()
partition by dt
order by id; CREATE TABLE test.test_all2 on cluster default_cluster as test.test_local2 ENGINE = Distributed('default_cluster', 'test', 'test_local2', sipHash64(id));

data Map(String, String) :这就定义了一个map类型字段,查询时候可以这样查:

select data['key'] from test.test_all2 limit 5

对于json,ck也是可以解的。

select JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b')
-- 结果
'[-100, 200.0, 300]' select JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 'a')
-- 结果
'hello'

更详细官方文档:https://clickhouse.com/docs/zh/sql-reference/functions/json-functions

关于成本

相比较而言,ck是能节省成本的,运维是这么说的。经常扩容磁盘,而计算性能只扩容了一次。

clickhouse使用心得的更多相关文章

  1. ClickHouse源码笔记1:聚合函数的实现

    由于工作的需求,后续笔者工作需要和开源的OLAP数据库ClickHouse打交道.ClickHouse是Yandex在2016年6月15日开源了一个分析型数据库,以强悍的单机处理能力被称道. 笔者在实 ...

  2. clickhouse使用的一点总结

    clickhouse据说是用在大数据量的olap场景列式存储数据库,也有幸能够用到它在实际场景中落地.本篇就来说说简单的使用心得吧. 1. 整体说明 架构啥的,就不多说了,列式存储.大数据量.高性能. ...

  3. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  4. NoSql数据库使用半年后在设计上面的一些心得

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...

  5. 我的MYSQL学习心得(二) 数据类型宽度

    我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  6. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  7. 我的MYSQL学习心得(四) 数据类型

    我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...

  8. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  9. 我的MYSQL学习心得(六) 函数

    我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  10. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

随机推荐

  1. MySQL8 查询优化新工具 Explain Analyze

    1.什么是Explain Analyze? Explain 是我们常用的查询分析工具,可以对查询语句的执行方式进行评估(并非实际的执行情况,可能与实际情况存在较大差距),给出很多有用的线索. Expl ...

  2. C# 二十年语法变迁之 C# 7参考

    C# 二十年语法变迁之 C# 7参考 https://benbowen.blog/post/two_decades_of_csharp_iii/ 自从 C# 于 2000 年推出以来,该语言的规模已经 ...

  3. 扯淡的DevOps,我们开发根本不想做运维!

    引言 最初考虑引用" DevOps 已死,平台工程才是未来"作为标题,但这样的表达可能太过于绝对.最终,决定用了"扯淡的"这个词来描述 DevOps,但这并不是 ...

  4. SATA学习笔记——OOB信号

    一.SATA物理层概述 说OOB之前,首先得了解一下SATA结构以及物理层的含义. SATA主要包括:应用层(Application Layer), 传输层(Transport Layer),链路层( ...

  5. 解决iso方式安装win10找不到固态硬盘!!!

    问题说明 朋友的一台联想小新笔记本需要安装win10,我给弄了个iso启动U盘,但是在选择安装盘时找不到笔记本的固态硬盘... 问题原因 联想的锅! 以联想为例,出厂系统的BIOS内,SATA Con ...

  6. Maven如何打包可执行jar包

    假设我有一个maven项目叫:hello-world 新建一个HelloWorld类: package com.dylan.mvnbook.helloworld; public class Hello ...

  7. 本地启动RocketMQ未映射主机名产生的超时问题

    问题描述 参考RocketMQ官方文档在本地启动一个验证环境的时候遇到超时报错问题. 本地环境OS:CentOS Linux release 8.5.2111 首先,进入到RocketMQ安装目录,如 ...

  8. KPTP 汇报模板

    1.什么是KPTP 它是由4个单词:Keep.Problem.Try.Plan的首字母组成的. K:keep,今天做了哪些工作: P:problem,遇到了哪些问题: T:try,计划尝试如何解决这些 ...

  9. OpenCV开发笔记(六十):红胖子8分钟带你深入了解Harris角点检测(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  10. ASP.NET Core MVC应用模型的构建[4]: Action的选择

    ControllerModel类型的Actions属性包含一组描述有效Action方法的ActionModel对象.对于定义在Controller类型中的所有方法,究竟哪些方法才能成为有效的Actio ...