clickHouse分区和分片详解

1. 什么是clickhouse?

clickHouse接入指南和排坑日记
clickHouse分区和分片详解

ClickHouse是一个面向联机分析处理(OLAP)的开源的面向列式存储的DBMS,简称CK, 与Hadoop, Spark相比,ClickHouse很轻量级,由俄罗斯第一大搜索引擎Yandex于2016年6月发布, 开发语言为C++。
ClickHouse的特点:

  1. 开源的列存储数据库管理系统,支持线性扩展,简单方便,高可靠性
  2. 容错跑分快:比Vertica快5倍,比Hive快279倍,比MySQL快800倍,其可处理的数据级别已达到10亿级别;
  3. 功能多:支持数据统计分析各种场景,支持类SQL查询,异地复制部署

具体介绍和安装教程可以参考这篇文章
clickhouse官方地址
clickhouse中文文档地址

2. 分区和分片

2.1 分区

分区是表的分区,是解决大数据存储的常见解决方案,具体的DDL操作关键词是 PARTITION BY,指的是一个表按照某一列数据(比如日期)进行分区,对应到最终的结果就是不同分区的数据会写入不同的文件中。功能会比较类似于mysql的索引,主要是为了解决,有时候我们查询只关心表中的一部分数据,建表时引入partition概念,可以按照对应的分区字段,找出对应的文件进行查询展示,防止查询中会扫描整个表内容,消耗很多时间做没必要的工作。

2.2 分片

clickhouse的分片。其实也就是一个视图聚合的功能,复用了数据库的分区,相当于在原有的分区下,作为第二层分区, 是在不同节点/机器上的体现。clickhouse可以支持读取每个分片上的内容的集合。底层是通过Distributed这个引实现的。默认是随机写到某个分片,但是也可以自己去指定写到具体某台机器上。
Distributed引擎的官网介绍

分区和分片的具体关系如下:
在这里插入图片描述
数据分区-允许查询在指定了分区键的条件下,尽可能的少读取数据
数据分片-允许多台机器/节点同并行执行查询,实现了分布式并行计算

3. 分区相关操作

3.1 创建分区表


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],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]

3.2 删除分区

alter table [db.]table_name drop partition  key [ON CLUSTER cluster]

3.3 查询分区信息

select * from system.parts where table='table_name'

4. 分片原理

在分布式模式下,ClickHouse会将数据分为多个分片,并且分布到不同节点上。不同的分片策略在应对不同的SQL Pattern时,各有优势。ClickHouse提供了丰富的sharding策略,让业务可以根据实际需求选用。

1) random随机分片:写入数据会被随机分发到分布式集群中的某个节点上。

2) constant固定分片:写入数据会被分发到固定一个节点上。

3) column value分片:按照某一列的值进行hash分片。

4) 自定义表达式分片:指定任意合法表达式,根据表达式被计算后的值进行hash分片。

数据分片,让ClickHouse可以充分利用整个集群的大规模并行计算能力,快速返回查询结果。
更重要的是,多样化的分片功能,为业务优化打开了想象空间。比如在hash sharding的情况下,JOIN计算能够避免数据shuffle,直接在本地进行local join;支持自定义sharding,可以为不同业务和SQL Pattern定制最适合的分片策略;利用自定义sharding功能,通过设置合理的sharding expression可以解决分片间数据倾斜问题等。
另外,sharding机制使得ClickHouse可以横向线性拓展,构建大规模分布式集群,从而具备处理海量数据的能力。

不过ClickHouse的集群的水平拓展目前是一个瓶颈,因为历史数据的存在, 避免新增节点之后的数据倾斜是个难点。

5. clickhouse连表查询

5.1 Join 查询

我们都知道 Join 的常见连接类型分为以下几种:

  • INNER JOIN
  • OUTER JOIN
  • CROSS JOIN
  • SEMI JOIN
  • ANTI JOIN

Join 的常见算法实现包含以下几种:

  • Nested Loop Join
  • Sort Merge Join
  • Hash Join

分布式系统实现 Join 数据分布的常见策略有:

  • Shuffle Join
  • Broadcast Join
  • Colocate/Local Join

Colocate/Local Join 就是指多个节点 Join 时没有数据移动和网络传输,每个节点只在本地进行 Join,能够本地进行 Join 的前提是相同 Join Key 的数据分布在相同的节点。

5.2 clickHouse单机JOIN实现

ClickHouse 单机JOIN操作默认采用HASH JOIN算法,可选MERGE JOIN算法。其中,MERGE JOIN算法数据会溢出到磁盘,性能相比前者较差。

ClickHouse JOIN查询语法和mysql的join比较像,主要差别是global修饰符:

SELECT <expr_list>FROM <left_table>[GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ASOF] JOIN <right_table>(ON <expr_list>)|(USING <column_list>) ...

ClickHouse 的 HASH JOIN算法实现逻辑大概如下:

  • 从right_table 读取该表全量数据,在内存中构建HASH MAP;
  • 从left_table 分批读取数据,根据JOIN KEY到HASH MAP中进行查找,如果命中,则该数据作为JOIN的输出;
    在这里插入图片描述

从这个实现中可以看出,如果right_table的数据量超过单机可用内存空间的限制,则JOIN操作无法完成。通常,两表JOIN时,将较小表作为right_table可以更好的提升性能。

5.3 clickHouse分布式JOIN实现

ClickHouse 的分布式JOIN查询可以分为两类,带GLOBAL关键字的,和不带GLOBAL关键字的情况,不带GLOBAL关键字的查询,每个节点都会全量去拉右表数据,然后和本地的左表进行关联匹配,存在查询放大的问题;加上GLOBAL关键字,initiator(作为计算协调者的节点)会先进行右表的查询,然后将结果发送给每个节点,再各个节点进行左表的关联匹配,避免了其他节点重复计算。所以,如果是分布式clickhouse集群,join查询建议使用GLOBAL修饰

比如下面这条sql,针对是否带GLOBAL关键字的执行步骤分别如下:

SELECT a_.i, a_.s, b_.t FROM a_all as a_ JOIN b_all AS b_ ON a_.i = b_.i

其中,a_all, b_all为分布式表,对应的本地表名为a_local, b_local

无GLOBAL关键字的JOIN实现:

  • initiator 收到查询请求

  • initiator 执行分布式查询,本节点和其他节点执行SELECT a_.i, a_.s, b_.t FROM a_local AS a_ JOIN b_all as b_ ON a_.i = b_.i即左表分布式表更改为本地表名。该SQL在集群范围内并行执行。

  • 集群节点收到2)中SQL后,分析出右表时分布式表,则触发一次分布式查询:SELECT b_.i, b_.t FROM b_local AS b_ 集群各节点并发执行,并合并结果,记为subquery.

  • 集群节点完成3)中SQL执行后,执行 SELECT a_.i, a_.s, b_.t FROM a_local AS a_ JOIN subquery as b_ ON a_.i = b_.i其中subquery表示2中执行的结果

  • 各节点执行完成JOIN计算后,向initiator节点发送数据
    在这里插入图片描述
    GLOBAL JOIN 计算过程如下:

  • initiator 收到查询请求

  • initiator 和集群其他节点均执行SELECT b_.i, b_.t FROM b_local AS b_ 即左表分布式表更改为本地表名。该SQL在集群范围内并行执行。汇总结果,记录为subquery。

  • initiator 将2)中subquery发送到集群中其他节点,并触发分布式查询:SELECT a_.i, a_.s, b_.t FROM a_local AS a_ JOIN subquery as b_ ON a_.i = b_.i其中subquery表示2)中执行的结果

  • 各节点执行完成JOIN计算后,向initiator节点发送数据

在这里插入图片描述

5.4 数据预分布实现Colocate JOIN

写入数据时,不采用random随机分片的方式,而是通过select * from system.cluster获取集群的列表,然后针对JOIN KEY和集群内机器列表,进行hash的方式,将相同的JOIN KEY的数据写到同一个节点上,这样可以将分布式JOIN转为为节点的本地JOIN,极大减少了查询放大问题。

如果如下操作:

  • 将涉及JOIN的表按JOIN KEY分片,保证相同的JOIN KEY的数据在同一个节点上

  • 修改sql,将JOIN中右表换成相应的本地表,针对上面的示例sql,则修改为如下:

SELECT a_.i, a_.s, b_.t FROM a_all as a_ JOIN b_local AS b_ ON a_.i = b_.i
  • 9
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值