ClickHouse 优化

本文介绍了ClickHouse的表优化技巧,包括使用日期类型存储日期字段,避免Nullable类型,合理分区和建立索引,以及设置TTL。在写入查询优化方面,建议避免小批量写入,使用count()代替count(列),避免select*,减少虚拟列的使用,利用uniqCombined提高去重性能,使用物化视图和智能JOIN策略。此外,还提到了分布式表使用global关键字来提升查询效率。
摘要由CSDN通过智能技术生成

1、表优化

1.日期字段避免使用String存储

在Hive中对于日期数据我们经常使用String类型存储,但是在ClickHouse中建表时针对日期类型数据存储建议使用日期类型存储,不使用String类型存储,因为在使用到日期时日期类型可以直接处理,String类型的日期数据还需要使用函数进行处理,执行效率低。

2.Nullable值处理

在ClickHouse表中数据存储时,对于一些列尽量不使用Nullable类型存储,因为此类型需要单独创建额外的文件来存储NULL的标记并且Nullable类型列无法被索引,会拖累性能,在数据存储时如果有空值时,我们可以选择在业务中没有意义的值来替代NULL值。

3.分区和索引

ClickHouse中一般选择按天分区,可以指定tuple()指定多个列为组合分区。如果不按天分区,每个分区数据量控制在800~1000万为宜。
建表时通过order by 指定索引列,可以指定tuple(),指定多个列为索引列,指定索引列时最好满足高基列在前、查询频率大的列在前的原则。基数过大的列不适合作为索引列,因为如果某列基数特别大,这种情况有索引和没索引效果一样。

4.建表指定TTL

如果表不是必须保存全量历史数据,建议指定TTL,以免去手动清除过期数据的麻烦。

2、写入查询优化

1.避免小批量数据写入

尽量避免单条和小批量插入、删除操作,会产生大量小分区文件,给后台Merge带来压力。

2.count优化

在ClickHouse中向查询数据总条数时,使用count() 代替count(列)查询,因为使用count()查询会自动寻找数据目录中的“count.txt”文件读取数据总条目,性能极高。如果使用count(列)相当于扫描全表读取总数据量。

3.避免使用select *

数据量太大时应避免使用select * 查询,这种查询会将表中所有字段都查询出来,IO消耗大,查询字段越少消耗的IO资源就越少,性能就会越高。

4.避免构建虚拟列

如果非必要尽量避免在查询时构建虚拟列,虚拟列非常消耗资源,造成性能浪费,可以考虑在前端进行处理或者在表中构建实际的列进行额外存储。

5.使用uniqCombined代替count(distinct)

使用uniqCombined替代distinct性能可提升10倍以上,uniqCombined 底层采用类似HyperLogLog算法实现,如能接收2%左右的数据误差,可直接使用这种去重方式提升查询性能。

6.使用物化视图

对于一些确定的数据模型,可以将统计指标通过物化视图的方式进行构建,这样可避免数据查询时重复计算的过程,同样在后期也可以构建Projection
投影来替代物化视图。

7.Join关联相关

当多表关联查询时,查询的数据仅来源于一张表时,可考虑用IN代替JOIN,速度会更快。

例如:

采用join

select count(distinct a.CounterID) as cnt  from hits_v1 as a  join visits_v1  as b on a.CounterID = b.CounterID

采用 where … in … 的方式

select count(distinct CounterID) as cnt from hits_v1 where CounterID in (select  CounterID from visits_v1);

8.分布式表使用global

对分布式表使用join 或者 in时,ClickHouse会将当前SQL分发到各个ClickHouse节点上执行,例如有如下SQL:

select a.id,a.name,b.score from a join b on a.id = b.id

如果以上a表和b表都是分布式表,ClickHouse集群有3个节点,那么上面SQL会分发到ClickHouse所有节点执行,b表会在每个节点上收集其他节点对应b表数据并放在内存,这样的话,每个ClickHouse节点都会从对应的3台节点上将b表数据进行汇集。

如果使用global关键字,执行如下SQL:

select a.id,a.name,b.score from a global join b on a.id = b.id

这样执行SQL的话,相当于在当前写SQL节点会将查询得到b表所有数据,然后统一分发到其他ClickHouse各个节点上,然后每个节点在执行与a表关联。这样使用global就减少了集群之间查询次数。
所以在使用分布式表进行join或者in时,可以优先考虑使用global,使用用法如下:

select a.id,a.name,b.score from a global join b on a.id = b.id
select a.id,a.name from a global  where a.id global in (select id from b)

9.避免使用final

ClickHouse中我们可以使用ReplacintMergeTree来对数据进行去重,这个引擎可以在数据主键相同时根据指定的字段保留一条数
据,ReplacingMergeTree只是在一定程度上解决了数据重复问题,由于自动分区合并机制在后台定时执行,所以并不能完全保障数据不重复。我们需要在查询时在最后执行final关键字,final执行会导致后台数据合并,查询时如果有final效率将会极低,我们应当避免使用final查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值