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集群,有较高的成本。
相关推荐
csdn2015_2 小时前
kafka如何确保消息不丢失
数据库·分布式·kafka
952362 小时前
RabbitMQ - 高级特性
java·spring boot·分布式·后端·rabbitmq
Database_Cool_3 小时前
阿里云 PolarDB-X vs TiDB 分布式数据库选型指南
数据库·分布式·阿里云·tidb
数据库小学妹3 小时前
分布式数据库架构怎么选?三种路线对比+迁移避坑指南
数据库·分布式·分布式数据库·数据库架构·数据迁移·数据库选型
大师兄66683 小时前
HarmonyOS7 分布式流转:手机到平板无缝接续案例
分布式·跨设备·harmonyos7·分布式流转
一只积极向上的小咸鱼3 小时前
多机Docker + InfiniBand 分布式运行实操手册
分布式·docker·容器
AndrewHZ4 小时前
【LLM技术全景】混合精度与分布式训练:训练大模型的工程奥秘
人工智能·分布式·深度学习·算法·ai·语言模型·llm
ffqws_13 小时前
Redis 分布式锁:基于 Redisson 的实现与面试高频问答
redis·分布式·面试
六bring个六18 小时前
open Harmony中分布式软总线的学习任务清单
分布式·学习·c/c++·open harmony
wuqingshun31415918 小时前
说一下 Kafka 中关于事务消息的实现?
分布式·kafka