ClickHouse是俄罗斯Yandex 2016年开源的列式存储数据库(DBMS)与hbase类似,使用C++编写。主要用于 在线分析处理查询(OLAP),常用于SQL查询进行数据分析生成数据报告,大数据领域-数仓。
官网在线测试
官网测试数据集
20.6.3开始支持执行 explain
20.8开始支持数据同步到mysql
id | name | age |
---|---|---|
1 | zhangsan | 10 |
2 | lisi | 11 |
3 | wangwu | 12 |
| 1 | zhangsan | 10 | 2 | lisi | 11 | 3 | wangwu | 12 |
好处是想查某个人所有的属性时,可以通过一次磁盘查找加顺序读取就可以。但是当想查所有人的年龄时,需要不停的查找,或者全表扫描才行,遍历的很多数据都是不需要的。
| 1 | 2 | 3 | zhangsan | lisi | wangwu | 11 | 12 | 13 |
这时想查所有人的年龄只需把年龄那一列拿出来就可以
对标准SQL语法支持的比较好,包括DDL和DML及相关函数、权限管理、数据备份与恢复。
目前包括合并树(merge tree)、日志、接口、和其他四类20多种引擎
采用LSM Tree结构,数据写入后定期在后台compaction(合并),数据导入时都是顺序写append(速度快),写入后数据段不可更改,compaction时也是多个段merge sort后顺序写回磁盘
数据分区可避免全表扫描。将数据划分为多个partition,每个partition再进一步划分为多个index。然后利用多核CPU分别处理其中一部分来实现并行数据处理。这种设计下,单条query就能利用整机所有CPU,极大提高查询效率。弊端是单条query就使用多核CPU不利于并发多条查询,因此不适用于高qps的查询业务
/etc/clickhouse-server
https://clickhouse.com/docs/zh/sql-reference/data-types/
整型、浮点型(Float32、Float64)布尔型、Decimal型、字符串型、枚举型(数据之间绑定关系)、数组型
时间型
date 年月日
datetime 年月日时分秒
datetime64 年月日时分秒毫秒
…
MySQL引擎用于将远程的MySQL服务器中的表映射到ClickHouse中,并允许您对表进行INSERT和SELECT查询,以方便您在ClickHouse与MySQL之间进行数据交换
https://clickhouse.com/docs/zh/engines/database-engines/mysql/
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
...
) ENGINE = MySQL('host:port', 'database', 'table', 'user', 'password'[, replace_query, 'on_duplicate_clause'])
SETTINGS
[connection_pool_size=16, ]
[connection_max_tries=3, ]
[connection_wait_timeout=5, ] /* 0 -- do not wait */
[connection_auto_close=true ]
;
表引擎决定了如何存储数据。
表引擎的使用方式须显式在创建表时定义该表使用的引擎,以及引擎使用的相关参数。(名称大小写敏感)
https://clickhouse.com/docs/zh/engines/table-engines/
Tinylog:不支持索引、以列文件形式保存,一般保存较少数据的小表
create table t_tinylog ( id String, name String) engine=TinyLog;
Memory:不支持索引、数据以未压缩的原始形式保存在内存中,用的较少
MergeTree:支持索引和分区,生产环境最常用
https://clickhouse.com/docs/zh/engines/table-engines/mergetree-family/mergetree/#mergetree
# 建表
create table t_order_mt(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =MergeTree
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
# 插入
insert into t_order_mt values
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
(102,'sku_002',2000.00,'2020-06-01 11:00:00'),
(102,'sku_004',2500.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 13:00:00'),
(102,'sku_002',12000.00,'2020-06-01 13:00:00'),
(102,'sku_002',600.00,'2020-06-02 12:00:00');
ORDER BY (排序必选)。
PARTITION BY (分区可选)
ls /var/lib/clickhouse/data/default/t_order_mt
20200601_1_11_1 20200602_14_14_0 20200602_2_14_3 format_version.txt
20200601_13_13_0 20200602_2_12_2 detached
手动合并表所有分区
optimize table t_order_mt final;
手动合并表指定分区
optimize table t_order_mt partition '20200602' final;
PRIMARY KEY(主键可选)
默认情况下主键跟排序键(由 ORDER BY 子句指定)相同,通常不需要修改。
CK中只提供了数据的一级索引,但是却不是唯一约束。这就意味着是可以存在相同 primary key 的数据。上述案例索引id就是重复的
官网
增
insert into st_order_mt values
(101,'sku_001',1000.00,'2020-06-01 12:00:00') ,
删
alter table st_order_mt delete where sku_id ='sku_001';
改
alter table st_order_mt update total_amount=toDecimal32(2000.00,2) where id =205;
查
select * from st_order_mt_all2 where id = 205;
参考文章:https://blog.csdn.net/qq_28603127/article/details/109788763
副本只能同步数据,不能同步表结构,所以我们需要在每台机器上自己手动建表
参数说明:ReplicatedMergeTree 中,第一个参数是分片的 zk_path 一般按照:/clickhouse/table/{shard}/{table_name} 的格式写,如果只有一个分片就写 01 即可。第二个参数是副本名称,相同的分片副本名称不能相同。
create table t_order_rep2 (
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =ReplicatedMergeTree('/clickhouse/table/01/t_order_rep','rep_76')
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
create table t_order_rep2 (
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine =ReplicatedMergeTree('/clickhouse/table/01/t_order_rep','rep_77')
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
insert into t_order_rep2 values
(101,'sku_001',1000.00,'2020-06-01 12:00:00'),
(102,'sku_002',2000.00,'2020-06-01 12:00:00'),
(103,'sku_004',2500.00,'2020-06-01 12:00:00'),
(104,'sku_002',2000.00,'2020-06-01 12:00:00'),
(105,'sku_003',600.00,'2020-06-02 12:00:00');
验证
select * from t_order_rep2;
SELECT *
FROM t_order_rep2
Query id: 5b1c117a-ea95-41aa-b96c-4673298ccae2
┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 101 │ sku_001 │ 1000.00 │ 2020-06-01 12:00:00 │
│ 102 │ sku_002 │ 2000.00 │ 2020-06-01 12:00:00 │
│ 103 │ sku_004 │ 2500.00 │ 2020-06-01 12:00:00 │
│ 104 │ sku_002 │ 2000.00 │ 2020-06-01 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘
┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 105 │ sku_003 │ 600.00 │ 2020-06-02 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘
5 rows in set. Elapsed: 0.006 sec.
https://galaxy.ansible.com/alexeysetevoi/clickhouse 该role包含对clickhouse安装以及各种配置管理(集群分片和副本、权限、创建db、zk相关、指定安装版本等),不同版本之间稍加修改即可使用。
CK单点和集群安装方式一样,单点与集群最大的区别在于增加了/etc/clickhouse-server/conf.d/zookeeper-servers.xml zookeeper相关配置(默认文件名metrika.xml)。当有这个配置后CK单点会组成集群。但是要注意,CK集群和ES不同,分片与副本需要通过配置文件人工分配。 通常在/etc/clickhouse-server/conf.d/clickhouse_remote_servers.xml 中指定。
/etc/clickhouse-server/conf.d/zookeeper-servers.xml
<yandex>
<zookeeper>
<node index="1">
<host>10.18.251.76host>
<port>12181port>
node>
<node index="2">
<host>10.18.251.77host>
<port>12181port>
node>
<node index="3">
<host>10.18.251.91host>
<port>12181port>
node>
zookeeper>
yandex>
/etc/clickhouse-server/conf.d/clickhouse_remote_servers.xml
<yandex>
<remote_servers>
<s1r2>
<shard>
<internal_replication>trueinternal_replication>
<replica>
<host>10.18.251.76host>
<port>9000port>
replica>
<replica>
<host>10.18.251.77host>
<port>9000port>
replica>
shard>
s1r2>
remote_servers>
yandex>
在集群s1r2中创建表st_order_mt,发现配置定义中的副本节点和分片节点会同步
create table st_order_mt on cluster s1r2 (
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
) engine
=ReplicatedMergeTree('/clickhouse/tables/{shard}/st_order_mt','{replica}')
partition by toYYYYMMDD(create_time)
primary key (id)
order by (id,sku_id);
Query id: a7cef48a-ebdf-4419-8d06-e6fcae06bfcb
┌─host─────────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ 10.18.251.77 │ 9000 │ 0 │ │ 1 │ 1 │
└──────────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
┌─host─────────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ 10.18.251.76 │ 9000 │ 0 │ │ 0 │ 0 │
└──────────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
2 rows in set. Elapsed: 0.258 sec.
创建Distribute分布式表 st_order_mt_all2
参数说明:
Distributed(集群名称,库名,本地表名,分片键)
分片键必须是整型数字,所以用 hiveHash 函数转换,也可以 rand()
create table st_order_mt_all2 on cluster s1r2
(
id UInt32,
sku_id String,
total_amount Decimal(16,2),
create_time Datetime
)engine = Distributed(s1r2,default, st_order_mt,hiveHash(sku_id));
Query id: 25da6baa-8b7a-4f5f-9644-f1db529d184d
┌─host─────────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ 10.18.251.77 │ 9000 │ 0 │ │ 1 │ 0 │
│ 10.18.251.76 │ 9000 │ 0 │ │ 0 │ 0 │
└──────────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘
2 rows in set. Elapsed: 0.124 sec.
insert into st_order_mt_all2 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');
结论:通过分布式表查询可看到所有数据;查看本地表则只可以看到对应分片的数据。
https://clickhouse.com/docs/en/sql-reference/statements/explain/#explain-types
EXPLAIN [AST | SYNTAX | PLAN | PIPELINE] [setting = value, ...]
SELECT ... [FORMAT ...]
plan 实例
简单查询
explain plan select arrayJoin([1,2,3,null,null]);
复杂查询
explain header=1, actions=1,description=1 select number from
system.numbers limit 10;
SYNTAX 实例
//先做一次查询
SELECT number = 1 ? 'hello' : (number = 2 ? 'world' : 'atguigu') FROM
numbers(10);
//查看语法优化
EXPLAIN SYNTAX SELECT number = 1 ? 'hello' : (number = 2 ? 'world' :
'atguigu') FROM numbers(10);
建表时能用数值型或日期时间型表示的字段就不要用字符串,因为 DateTime 不需要经过函数转换处理,执行效率高、可读性好。
create table t_type2(
id UInt32,
sku_id String,
total_amount Decimal(16,2) ,
create_time Int32
) engine =ReplacingMergeTree(create_time)
partition by toYYYYMMDD(toDate(create_time)) –-需要转换一次,否则报错
primary key (id)
order by (id, sku_id);
https://clickhouse.com/docs/zh/sql-reference/data-types/nullable/
官方建议:Nullable 类型几乎总是会拖累性能,因为存储 Nullable 列时需要创建一个额外的文件来存储 NULL 的标记,并且 Nullable 列无法被索引。因此除非极特殊情况,应直接使用字段默认值表示空,或者自行指定一个在业务中无意义的值(例如用-1 表示没有商品ID)
如果表中不是必须保留全量历史数据,建议指定 TTL(生存时间值),可以免去手动过期历史数据的麻烦,TTL 也可以通过 alter table 语句随时修改。
ClickHouse 不支持设置多数据目录,建议使用SSD提升读写性能。
默认情况下, where 条件会自动优化成 prewhere。
但在以下情况,需要手动指定:
采样修饰符只有在 MergeTree engine 表中才有效,且在创建表时需要指定采样策略。
SELECT Title,count(*) AS PageViews
FROM hits_v1
SAMPLE 0.1 #代表采样 10%的数据,也可以是具体的条数
WHERE CounterID =57
GROUP BY Title
ORDER BY PageViews DESC LIMIT 1000
数据量太大时应避免使用 select * 操作,查询的性能会与查询的字段大小和数量成正比,字段越少,消耗的 io 资源越少,性能就会越高。
反例:
select * from datasets.hits_v1;
正例:
select WatchID,
JavaEnable,
Title,
GoodEvent,
EventTime,
EventDate,
CounterID,
ClientIP,
ClientIP6,
RegionID,
UserID
from datasets.hits_v1;
分区裁剪就是只读取需要的分区,在过滤条件中指定。、
select WatchID,
JavaEnable,
Title,
GoodEvent,
EventTime,
EventDate,
CounterID,
ClientIP,
ClientIP6,
RegionID,
UserID
from datasets.hits_v1
where EventDate='2014-03-23';
性能可提升 10 倍以上,uniqCombined 底层采用类似 HyperLogLog 算法实现,能接收 2%左右的数据误差,可直接使用这种去重方式提升查询性能。Count(distinct )会使用 uniqExact精确去重。
不建议在千万级不同数据上执行 distinct 去重查询,改为近似去重 uniqCombined
反例:
select count(distinct rand()) from hits_v1;
正例:
SELECT uniqCombined(rand()) from datasets.hits_v1
当多表联查时,查询的数据仅从其中一张表出时,可考虑用 IN 操作而不是 JOIN
多表 join 时要满足小表在右的原则,右表关联时被加载到内存中与左表进行比较,ClickHouse 中无论是 Left join 、Right join 还是 Inner join 永远都是拿着右表中的每一条记录到左表中查找该记录是否存在,所以右表必须是小表。
两张分布式表上的 IN 和 JOIN 之前必须加上 GLOBAL 关键字,右表只会在接收查询请求的那个节点查询一次,并将其分发到其他节点上。如果不加 GLOBAL 关键字的话,每个节点都会单独发起一次对右表的查询,而右表又是分布式表,就导致右表一共会被查询 N²次(N是该分布式表的分片数量),这就是查询放大,会带来很大开销。
普通视图不保存数据,保存的仅仅是查询语句,查询的时候还是从原表读取数据,可以将普通视图理解为是个子查询。
物化视图则是把查询的结果根据相应的引擎存入到了磁盘或内存中,对数据重新进行了组织,你可以理解物化视图是完全的一张新表。
优点:查询速度快
缺点:占用机器资源
对于一些确定的数据模型,可将统计指标通过物化视图的方式进行构建,这样可避免查询时重复计算的过程,物化视图会在有新数据插入时进行更新。
CREATE [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]table_name [TO[db.]name]
[ENGINE = engine] [POPULATE] AS SELECT ...
建表
CREATE TABLE hits_test
(
EventDate Date,
CounterID UInt32,
UserID UInt64,
URL String,
Income UInt8
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID)
SETTINGS index_granularity = 8192;
导入数据
INSERT INTO hits_test
SELECT
EventDate,
CounterID,
UserID,
URL,
Income
FROM hits_v1
limit 10000;
创建物化视图
#建表语句
CREATE MATERIALIZED VIEW hits_mv
ENGINE=SummingMergeTree
PARTITION BY toYYYYMM(EventDate) ORDER BY (EventDate, intHash32(UserID))
AS SELECT
UserID,
EventDate,
count(URL) as ClickCount,
sum(Income) AS IncomeSum
FROM hits_test
WHERE EventDate >= '2014-03-20' #设置更新点,该时间点之前的数据可以另外通过
#insert into select …… 的方式进行插入
GROUP BY UserID,EventDate;
##或者可以用下列语法,表 A 可以是一张 mergetree 表
CREATE MATERIALIZED VIEW 物化视图名 TO 表 A
AS SELECT FROM 表 B;
导入增量数据
#导入增量数据
INSERT INTO hits_test
SELECT
EventDate,
CounterID,
UserID,
URL,
Income
FROM hits_v1
WHERE EventDate >= '2014-03-23'
limit 10;
#查询物化视图
SELECT * FROM hits_mv;
导入历史数据
#导入增量数据
INSERT INTO hits_mv
SELECT
UserID,
EventDate,
count(URL) as ClickCount,
sum(Income) AS IncomeSum
FROM hits_test
WHERE EventDate = '2014-03-20'
GROUP BY UserID,EventDate
#查询物化视图
SELECT * FROM hits_mv;
解决方法:重启该节点
解决方法:在缺少表的数据副本节点上创建缺少的表,创建为本地表,表结构可以在其他数据副本通过 show crete table xxxx 获取。
表结构创建后,clickhouse 会自动从其他副本同步该表数据,验证数据量是否一致即可。
解决方法:
清空异常副本节点的 metadata 和 data 目录。
从另一个正常副本将 metadata 目录拷贝过来(这一步之后可以启动数据库,但是只有表结构没有数据)。
执行 sudo -u clickhouse touch /data/clickhouse/flags/force_restore_data
启动数据库。
启动异常节点,期间其他副本写入数据会自动同步过来,其他副本的建表 DDL 也会同步。
https://help.aliyun.com/document_detail/162815.html?spm=a2c4g.11186623.6.652.312e79bd17U8IO
从20.1.2.4开始内置支持prometheus监控,从而自动的将 metrics 、 events 和asynchronous_metrics 三张系统的表的数据发送给 Prometheus
config.xml 配置
/metrics
9363
true
true
true
true
grafana图表 id:
https://grafana.com/grafana/dashboards/14432
https://grafana.com/grafana/dashboards/13606
https://grafana.com/grafana/dashboards/13500
https://clickhouse.com/docs/zh/operations/backup/
参考part操作(繁琐)
https://github.com/AlexAkulov/clickhouse-backup
支持备份到s3
注:使用前务必充分测试备份与数据恢复,因为CK不同版本之间会有差异
users.xml -> profiles -> default 标签:
10000000000
5000000000
5000000000
0
0
查询优化参数
https://blog.csdn.net/qq_28603127/article/details/109788763