Clickhouse RepicatedReplacingMergeTree下推分析(二)

477 阅读4分钟

上一篇当中 我们讲了RepicatedReplacingMergeTree的下推原理,这一篇从Clickhouse的具体优化案例出发,谈一谈使用上的习惯

merge过程源码时序图

流程图: www.processon.com/view/link/6…

风轮-clickhouse merge流程.jpg

Merge Tree数据存储与数据标记

流程图: www.processon.com/view/link/6…

风轮 - Merge Tree数据存储与数据标记.jpg

优化原则

1.大表在左,小表在右,否则会造成右表加载数据量太大,大量消耗内存资源;

2.如果join的右表为大表,则需要将右表写成子查询,在子查询中将右表的条件都加上,并进行列裁剪,这样可以有效减少数据加载;

3.where条件中只放左表的条件,如果放右表的条件将在下推阶段右表条件不会生效,将右表条件放到join的子查询中去。

SQL执行计划分析

案例1:

explain select a.aid as aid, b.bid as bid, count(*) as ct from dw.t_a as a join dw.t_b as b on a.aid = b.aid group by aid, bid;

左表和右表的执行计划基本一样,先将远程节点上的表数据拉取到本地,然后和本地表的数据进行union操作,然后左表和右表进行join操作,最后进行group by操作

image.png

案例2:

explain select a.aid as aid, b.bid as bid, count(*) as ct from dw.t_b as b join dw.t_a as a on a.aid = b.aid group by aid, bid;

将左右表的顺序调换,此次表的执行顺序只是调换了一下,从左到右执行

767567567567.png

案例3:

explain select a.aid as aid, b.bid as bid, count(*) as ct from dw_local.t_a as a join dw_local.t_b as b on a.aid = b.aid where a.aid=1 group by aid, bid;

所有表都采用本地表,而不是分布式表,则在数据加载阶段不会拉取远程节点的数据

456464645.png

案例4:

explain select a.aid as aid, b.bid as bid, count(*) as ct from ( select * from dw.t_a ) as a join dw.t_b as b on a.aid = b.aid group by aid, bid;

左表为子查询时,左表也会走分布式表查询方式拉取数据,有文章说左表为子查询的情况下会导致左表走本地查询策略,不走分布式查询策略

dfgdfgdfgdf.png

Clickhouse的分区定义

  • ClickHouse 应用层面定义了 partition,用户指定 partition by 关键词设置不同的 partition,但是 partition 只是逻辑分区。真正存储到磁盘时按 part 来存储,每一个 part 一个文件夹,里面存储不同字段的.mrk和.bin文件,以及一个minmax_{PARTITION_KEY_COLUMN}.idx文件,不同 part 的 minmax 作为一个索引存储于内存。

  • 当查询的 WHERE 带有 partition key 时,首先会比较每一个 part 的 minmax 索引过滤不相关 parts。之后再根据 PARTITION BY 定义的规则过滤不相关 partition。 可是 partition 不是越小越好。 partitioning 并不会加速查询(有主键存在),过小的 partition 反而会导致大量的 parts 无法合并(MergeTree 引擎家族会在后台不断合并 parts),因为属于不同 partition 的 parts 无法合并。

最佳实践

  • 一个(Replicated)MergeTree 的 partition 大概 1 ~ 300GB
  • Summing/ReplacingMergeTree 的 partition 大概 400MB ~ 40GB
  • 查询时涉及尽量少 partition 插入时最好只有 1 ~ 2 个分区
  • 一张表维持 100 个分区以内

主键索引与mark索引之间的关系

  • Primary key index 主键是 ClickHouse 重要的索引,主键应该能有效排除大量无关的数据index_granularity,减少磁盘读取的字节数。ClickHouse 先将按index_granularity设置的大小(默认 8192)将数据分为一个个 granules 每个 granules 的第一行作为主键索引中的一个元素
  • 查询时在主键上使用二分查找跳过无关 granules 主键只能通过前缀命中索引
  • 每一个 part 内的.bin文件存储了 n 个 granules,用.mrk文件记录每一个 granules 在.bin文件的地址偏移 ClickHouse 会在后台不断合并同一个 partition 的不同 parts,直到大小/分布达到“预期” 主键的选择应该尽可能考虑周全,因为主键是无法修改的,只能建新表后数据迁移。

实践(针对(Replicated)MergeTree 引擎):

  • 永远会用于过滤条件的列 越重要的、基数越低的放左边
  • 主键中不要出现高基数索引, 一般最后一列可以为总体增长的时间字段
  • 将行的特征字段加入,将相似的行放一起,提高压缩率
  • 若主键包含主从关系,主放左边,从放右边
  • 越重要的,基数越低的放左边