一文读懂clickhouse 的normal join和global join区别

背景

同事问了我一个这样的问题,语义如下

表定义

定义两个分布式表
tablea 2 shard 1 replica user_id不是分区键
tableb 2 shard 1 replica user_id是分区键
请添加图片描述

SQL-1
select count(1) from tablea_all as ta join tableb_all as tb  on ta.user_id=tb.user_id
where ta.user_id=1
结果1

result is 1

SQL-2
select count(1) from tablea_all as ta global join tableb_all as tb  on ta.user_id=tb.user_id
where ta.user_id=1

两个SQL只是join 方式不一样而已

结果2

result is 2

结果竟然不一样???

思考

在我之前的知识体系里,clickhouse 的join分成三种

Shuffle Join

请添加图片描述
每条实线箭头线相当于一次join=4次
单独看表tableb 数据读了4次

Broadcast Join

请添加图片描述
每条实线箭头线相当于一次join=2次
单独看表tableb 数据读了2次

Colocate Join

请添加图片描述
每条实线箭头线相当于一次join=2次
单独看表tableb 数据读了2次

重看问题

因为之前一直认为的是join 指的就是Shuffle Join,但是这种会放大读,所以一直都是用的global join,但是join 和global join 语义上是一致的,都能够在分布表下表达出相同的语义,为啥这里的结果表现不一样了,这个问题一下把我把懵了,然后在google和baidu都看了相关的资料,基本上所有的资料都告诉我,事实就是这样了的,这里尤其以 火山引擎在行为分析场景下的ClickHouse JOIN优化. 这一篇文章的内容传播最广,很多其它人写的也就是在这上面加工的,可是这个事实和文章里的写的不一样呀,之前刚好字节数据team有一个活动,拉了一个群,于是在群里问了一下这个问题,可是没人搭理,哎本着实事求是的态度,然后去分析ck节点的日志信息,发现sql1 实现的Colocate Join 语义,只是在每个节点实现了tablea_local和tableb_local的语义,这样结果就是1,这一刻我有点怀疑是不是搜索引擎都是错的,join 根本都没有实现Shuffle Join,这个语义在分布式表的情况就是错的,我只相信我看到的,最后还有一招,在github上,找到clickhouse 提了一个issue,看看有没有大佬能解答我的疑惑,幸运的是中午提了issue,链接,晚上查看邮箱发现这个issue已经有回复了,回复中提到了distributed_product_mode 配置

distributed_product_mode

范围

仅适用于IN和JOIN子查询。

仅当FROM部分使用包含多个分片的分布式表时。

如果子查询涉及一个包含多个分片的分布式表。

可能值

deny—默认值。禁止使用这些类型的子查询(返回“Double distributed in/JOIN subquery is denied”异常)。

local-将子查询中的数据库和表替换为目标服务器(shard)的本地数据库和表,留下正常的in/JOIN。

global-将IN/JOIN查询替换为global IN/global JOIN。

allow-允许使用这些类型的子查询。

测试

测试使用 distributed_product_mode=allow/global sql1都能实现正确的语义,结果是2,于是我看了这个参数的默认值,结果是local,也就证实现了为啥结果是1,日志里显示的只有两个节点上执行的都是tablea_local join tableb_local
为啥为allow结果也是对的,all 实现的的Shuffle Join,从node 节点里的日志也能看出来有4次join
为啥为global结果也是对的,gobal会把sql重写也就是sql2的语义,所以也是对的

总结

这个问题历时周四,周五二天,几乎看了所有相关的资料,中间不断的怀疑自己的结论又推翻,最后找到了正确的答案,这个问题中,看节点里的查询sql日志能够增加我们对join在这种分布式表的环境下实现原理的理解。遇到问题时还是要实事求是,既要参考网上的资料,也要相信自己所看到的,实际上网上的资料也没有说错,只是没有说清楚这个配置distributed_product_mode的默认值,这个默认值是local也是能理解的,毕竟这样的join数据量是最少的。

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wending-Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值