Clickhouse的Join

Clickhouse单机join实现

clickhouse单机join操作默认采用hash join算法,可选用merge join。其中merge join算法数据会溢出到磁盘,性能相比前者差。本文主要介绍hashjoin实现的join操作。

  • 从right table读取该全量表数据,在内存中构建hashmap,从left table分批读取数据,根据join key到hash map中进行查找,如果命中,则该数据作为join输出。从实现可以看出,如果right table数据量超过单机可用内存限制时候,则join操作无法完成。通常,两表join时,将较小的作为right join

Clickhouse 分布式Join

join中涉及到的left_table和right_table是分布式表
有以下几种方式:

  • Broadcast JOIN
  • Shuffle Join
  • Colocate JOIN
    clickhouse集群并未实现完整意义上的shuffle join,实现了类似broadcast join,通过事先完成数据重分布,能够实现colocate join

clickhouse的分布式join查询可以分为两类,带global关键字的,和不带global关键字的情况。

普通join实现

无global关键字的join如何实现:

  • initiator将sql左表分布式表 S 替换成本地表,形成 S‘
  • 将S’分发到集群的每个节点
  • 当集群节点执行S‘,并将结果汇总到initiator节点
  • initiator节点将结果返回给客户端。如果右表是分布式表,则及群众每个节点会去执行分布式查询,就会存在一个非常严重的读放大现象。假设集群有N个节点,则右表查询会在集群中执行N*N次。

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_cloal。则该sql在分布式查询执行的时间顺序为:

  • initiator收到查询请求
  • initiator执行分布式查询,本届点和其他节点执行select a_.i,a_.s,b_.t from a_local as a_ join b_all as b_ on a_.i = b_.i,即左表更改为本地表
  • 集群节点收到请求后,分析出右表分布式表,在本地b_local查询结果,并计作subquery
  • 查到subquery后,在与a本地表进行join
  • 各节点执行完毕后,向initiator发送数据

shuflle join简化版,right表全量

Global join实现

global join计算过程如下:

  1. 若右表为子查询,则initiator完成子查询计算
  2. initiator将右表数据发送到其他集群节点
  3. 集群节点将本地左表与右表数据进行join计算
  4. 集群其他节点将结果发回给initiator节点计算
  5. initiator将结果汇总,发给客户端

global join可以看作一个不完整的broadcast join实现,如果join的右表数据量比较大,就会占用大量网络带宽,导致查询性能下降

global join将右表的查询在initiator节点上完成后,通过网络发送到其他节点,避免其他节点重复计算,从而避免查询方法。

分布式join最佳实践

  • 减少join右表数据量,小表作为右表,尽可能增加过滤条件
  • 利用global join避免查询放大带来性能损失
  • 数据预分布实现colocate join。将涉及join的表按join key分片
  • 查询时候将右边的表换成本地表

你可能感兴趣的:(clickhouse,clickhouse,join)