• clickhouse的Distributed分布式表查询的性能陷阱


    我们先假设我们的应用场景我们有一张分布式表和一张本地表:

    --分布式表
    create table table_distributed
    (
    uid int32, --学生编号
    class String --学生班级
    school String, --学校
    score int32,  --分数
    birthday DateTime --出生日期
    ) ENGINE= Distributed('cluster_test','my_db','table_local',uid);
    --本地表
    create table table_local
    (
    uid int32, --学生编号
    class String --学生班级
    school String, --学校
    score int32,  --分数
    birthday DateTime --出生日期
    ) ENGINE= MergeTree
    partition by toYYMMDD(birthday)
    order by uid
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    机器的拓扑结构图如下: A机器和B机器上分别存在本地表和分布式表,假设Sql语句是发送到了A机器上面的分布式表中,由A机器处理客户端的sql查询处理,现在我们在distributed_group_by_no_merge=0也就是默认情况下分析下以下两个sql的查询过程:
    第一类sql语句的查询过程:

    select uid,class,school 
    from table_distributed where toDate(birthday) >toDate('2022-09-00') and toDate(target_time) <toDate('2022-09-00')
    
    • 1
    • 2

    1.1 A机器接收到sql查询中对分布式表的查询请求
    1.2 A机器把分布式表替换成本地表后分别发送给A机器本地执行以及发送给B机器的本地执行
    1.3 A机器和B机器对本地表的查询操作是并行执行的,执行完成后会把结果也就是满足where条件的结果发往A机器
    1.4 A机器收到A机器和B机器的查询结果后,把结果发送给客户端,查询结束

    第二类sql语句group by聚合语句的查询过程 :

    select class,school,count() as uidNum
    from table_distributed where toDate(birthday) >toDate('2022-09-00') and toDate(target_time) <toDate('2022-09-00') group by class,school having uidNum > 10
    
    • 1
    • 2

    2.1 A机器接收到sql查询中对分布式表的查询请求
    2.2 A机器把分布式表替换成本地表后分别发送给A机器本地执行以及发送给B机器的本地执行
    2.3 A机器和B机器对本地表的查询操作是并行执行的,执行完成后会把结果也就是满足where条件的结果发往A机器
    2.4 A机器收到A机器和B机器的满足where条件的查询结果,也就是满足toDate(birthday) >toDate('2022-09-00') and toDate(target_time) 条件的所有记录
    2.5 A机器对前一步收到的所有的记录进行分组group by聚合操作,并且过滤掉所有count不满足条件的记录,然后把结果返回给客户端

    从前面这两个sql我们可以看出问题所在,当执行group by分组聚合操作时,并不是在每个本地表节点上分别执行完聚合操作后才把最终聚合的结果发送给A机器(入口节点)进行输出返回给客户端,而是每个本地的表节点只把满足了where条件的记录统统返回给了A机器(入口节点),由入口节点进行group by聚合并过滤(having),然后再把结果返回给客户端

    我们可以理解clickhouse这样做的原因是为了保证假设要进行group by的字段在多个本地表中同时存在的话,他需要每个本地表都先把数据传输给A机器(入口节点),然后入口节点才能把各个本地表的数据group by起来,比如假设A机器本地表 高一班有20个学生,B机器本地表高一班有30个学生,我们要查找高一班有多少个学生,确实需要先把数据都发送给A机器(入口节点),这样A机器才能统一group by聚合并得出高一班有50个学生的结论,不过由此同时我们也能知道对于这类查询,分布式表的查询性能并不高,原因是各个本地表上并不能聚合数据,他需要把本地表的数据大量的发送到A机器入口节点,网络的传输耗时是巨大的,主要的耗时也都会花费在数据网络传输上,这个时候即使多增加几个本地表,也不会对sql的查询耗时产生很大的作用,所以我们需要意识到这一点,对于这种group by分组聚合操作而言,多增加本地表并不能提升查询的性能

  • 相关阅读:
    MySQL高级篇4
    oracle-OVER(PARTITION BY... ORDER BY...)的使用
    简单描述 MySQL 中,索引,主键,唯一索引,联合索引 的区别,对数据库的性能有什么影响(从读写两方面)
    Python开发IDE的比较:PyCharm vs. VS Code vs. Jupyter
    无涯教程-Android - ImageButton函数
    差评回复模板
    这几个免费、商用图片素材网,你一定要知道。
    3.6、媒体接入控制
    我的第一个项目(十一) :飞机大战分包完成(简单阐述分包思路以及过程)
    云计算时代的运维: 职业发展方向与岗位选择
  • 原文地址:https://blog.csdn.net/lixia0417mul2/article/details/126925974