ClickHouse--19-- 分布式 GLOBAL IN 和 GLOBAL JOIN

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


一、前言

  • 当数据表包含多个分片的时候,我们需要将普通的本地查询转换为分布式查询。当然,这个转换动作是不需要用户自己进行的,在ClickHouse里面会由Distributed表引擎代劳。
  • Distributed表引擎的定位就好比是一个分表的中间件,它本身并不存储数据,而是分片的代理,能自动的将SQL查询路由到每个分片。

当我们面对Distributed表引擎查询的时候,它主要为我们做了3件事情:

  1. 发起远程调用,根据集群的配置信息,从当前节点向远端分片发起Remote远程查询调用
  2. 分布式表转本地表,在发送远程查询时,将SQL内的 _all表 转成 _local表
  3. 合并结果集,合并由多个分片返回的数据

二、案例分析

在大多数时候,面向Distributed表的SQL写法与本地查询没有多大区别。但当我们执行 IN 或者 JOIN 查询的时候,一不小心就容易掉到坑里,因为这些查询子句会面对多张数据表。

  • 为了便于演示,我们简化一下场景,用一个自查询的IN子句来解释说明,假设一张表的数据如下:
bash 复制代码
SELECT *
FROM test_query_local
 
┌─id─┬─repo─┐
│  1 │  100 │
│  2 │  100 │
│  3 │  100 │
│  3 │  200 │
│  4 │  200 │
└────┴──────┘

单机场景:

分布式场景:

  • 现在模拟分布式的场景,把这张表进行分片操作,将它们分布到CH5和CH6两个节点,且每个节点的数据数据如下:

第一种改法

将本地表 test_query_local 改成 分布式表 test_query_all

bash 复制代码
SELECT uniq(id)
FROM test_query_all
WHERE (repo = 100) AND (id IN 
(
    SELECT id
    FROM test_query_local
    WHERE repo = 200
))
 
┌─uniq(id)─┐
│        0 │
└──────────┘
 

你会发现返回的数据不对,进一步检查,原因是由 IN 子句引起的,因为它还在使用本地表 test_query_local

  • 这是什么原理呢?我们看下面这张图就明白了

第二种改法

在有了刚才的经验之后,现在把 IN 子句也替换成 _all 分布式表:

bash 复制代码
SELECT uniq(id)
FROM test_query_all
WHERE (repo = 100) AND (id IN 
(
    SELECT id
    FROM test_query_all
    WHERE repo = 200
))
 
┌─uniq(id)─┐
│        1 │
└──────────┘


第三种改法

查询放大怎么解决呢? ClickHouse为我们提供了解决方案,继续改造刚才的语句,增加 GLOBAL修饰符:
bash 复制代码
SELECT uniq(id) FROM test_query_all WHERE repo = 100 
AND id GLOBAL IN (SELECT id FROM test_query_all WHERE repo = 200)
  • 首先,将 GLOBAL 修饰的子句,单独进行了一次分布式查询;
  • 接着,将子句的结果汇总后,用内存临时表保存;
  • 最后,直接将临时表分发至每个分片节点,从而避免了查询放大的问题。

分布式JOIN

三、总结

问题:

好了,现在总结一下,当执行分布式JOIN 或者IN 查询的时候,会碰到几种问题:

  1. 查询不全,由于分片的数据不均,会出现查询数据不全的问题,所以JOIN表和 IN子句 也要使用 _all 分布式表;
  2. 查询放大,由于JOIN表 和 IN子句 也是 _all 分布式表,所以每个分片又会向其他远端的分片发起分布式查询,最终的查询次数是 N 的平方(N=分片数量);

策略1:GLOBAL IN 和 GLOBAL JOIN

  • 解决思路,使用 GLOBAL IN 和 GLOBAL JOIN 可以避免查询放大的问题。

策略2:跨表本地化

在ClickHouse集群中跨表进行Select查询时,采用Global IN/Global Join语句性能较为低下。分析原因,是在此类操作会生成临时表,并跨设备同步该表,导致查询速度慢。

  • 对于跨表查询,可以使用跨表本地化的策略。

解决方案

  • 解决方案:采用一致性hash,将相同主键数据写入同一个数据分片,在本地local表完成跨表联合查询,数据均来自于本地存储,从而提高查询速度。
  • 这种优化方案也有一定的潜在问题,目前ClickHouse尚不提供数据的Reshard能力,当Shard所存储主键数据量持续增加,达到磁盘容量上限需要分拆时,目前只能根据原始数据再次重建CK集群,有较高的成本。
相关推荐
降世神童2 小时前
大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署--完结
大数据·clickhouse·zookeeper
躺不平的理查德2 小时前
General Spark Operations(Spark 基础操作)
大数据·分布式·spark
talle20212 小时前
Zeppelin在spark环境导出dataframe
大数据·分布式·spark
渣渣盟3 小时前
大数据开发环境的安装,配置(Hadoop)
大数据·hadoop·分布式
Angindem3 小时前
SpringClound 微服务分布式Nacos学习笔记
分布式·学习·微服务
龙仔72511 小时前
离线安装rabbitmq全流程
分布式·rabbitmq·ruby
〆、风神14 小时前
Spring Boot 整合 Lock4j + Redisson 实现分布式锁实战
spring boot·分布式·后端
胡萝卜糊了Ohh15 小时前
kafka
分布式·kafka
桑榆080617 小时前
Spark-Streaming核心编程
大数据·分布式·spark