前言
在之前的文章中,已经跟铁子们分享了关于Clickhouse数据库CollapsingMergeTree表引擎的相关应用。最近在处理生产环境业务历史数据的过程中,发现还有一些容易踩坑的点在上次文章中没有记录,这里给铁子们再补充一下吧,如果后续你们有相同的业务需求,应该是比较有价值的干货。
引擎解释
在这里,我们结合官方文档可以看到,他是一个折叠引擎,是什么意思呢,就是说如果两条数据的所有字段,除了sidn字段是1和-1,那这两条数据在合并的过程中就会相互抵消,相当于删除操作。
为什么使用CollapsingMergeTree引擎
clickhouse中的删除和更新是异步的,那这样就有一个致命的问题,比如咱们的需求是先删除旧数据,再插入新数据,由于他是异步的,有可能在你插入之后,他才开始执行删除操作,就会导致数据丢失的情况。这个是我在生产环境做聚合报表的过程中发现的,大伙可以稍微留意一下,对于任何生产的数据都要持谨慎态度。
实战讲解
创建表
CREATE TABLE IF NOT EXISTS test_table
(
`pmp_id` Int64 COMMENT '项目ID',
`city` Int64 COMMENT '',
`statistic_date` DateTime COMMENT '统计日期',
`stu_num` Int64 DEFAULT 0 COMMENT '学生人数',
`class_room_num ` Int64 DEFAULT 0 COMMENT '教室数量',
`sign` Int8 COMMENT '标志位'
)
ENGINE = CollapsingMergeTree(sign)
PARTITION BY toYYYYMM(statistic_date)
PRIMARY KEY (pmp_id, city, statistic_date)
ORDER BY (pmp_id, city, statistic_date)
SETTINGS index_granularity = 8192;
我们这里创建一张测试表,注意sign字段是标志位字段
插入一条数据
insert into test_table(pmp_id,city,statistic_date,stu_num,class_room_num,sign) values (1002,'北京','2024-05-22 00:00:00',10,20,1);
插入数据后,我们发现数据录错了,那能不能直接删除或者更新,最好不要,数据量极少的话可能没啥问题,但是在做数据量比较大的业务时候,很容易出问题,正确的姿势如下:
- 将旧数据的sign标志位置为-1,因为我这里是根据时间定位的,所以直接根据statistic_date字段查出这段时间内的数据,先置为-1再插入,也可以用insert into xxx select …的形式直接在数据库层面处理。假设我这里已经查询出来旧数据,重新将sign置为-1后再插入数据库
insert into test_table(pmp_id,city,statistic_date,stu_num,class_room_num,sign) values (1002,'北京','2024-05-22 00:00:00',10,20,-1);
数据查询的正确姿势
数据插入后,其实这时候是有两条数据,一个是sign = 1, 一条是sign = -1,那如果这时候用户直接查询数据不就查出来是错误的数据吗?因为clickhouse的数据合并不一定是马上就合并,因为合并是一个非常消耗性能的操作,所以他会在数据库使用频率较低的时候触发。下面是查询的正确姿势:
SELECT
pmp_id,
city,
statistic_date,
sum( stu_num * sign ) AS stu_num,
sum( class_room_num * sign ) AS class_room_num
GROUP BY
pmp_id, city,statistic_date
HAVING
sum( sign ) > 0;
这里有个重要的注意点就是GROUP BY后面的字段必须要跟你建表时候的联合主键对应,不然你的数据聚合出来的结果大概率会有错误,尤其是你的数据反复清洗的时候,表里面会同时存在sign = 1和sign = -1的数据
温馨提醒:这里只是提供一个Demo,铁子们有时间最好看一下官方文档细品一下,clickhouse非常有用。技多不压身,多动手总是没错的。
容易踩坑的点
如果产品来了一个需求,要求加一个表示学生来源的字段source,并且要作为分组的字段之一,那历史数据怎么办呢?
有两种方式
- 方式一
创建关联进行关联,这个根据自己的业务需求和数据进行设计即可 - 方式二
重新创建一张新表,重新创建联合主键,把原来涉及这个表的查询的SQL全部改到这个表上面。为什么要讲这个呢,因为这里有一个坑点,就是上面说的,group by 字段,一定要把原来的group by 后面的字段改成最新联合主键,不然你聚合出来的数据肯定是不对的,尤其是当clickhouse数据触发合并的时候,你会一脸懵。
写在最后
好了,今天的坑点就分享到这里,官方文档已经附在文中,好学的你可以尝试抽时间去了解一下,蛮有用的,尤其是我们自己的业务拉起来之后,数据查询速度的提升真的效果,也给我们的搞钱的公众号"韭盾"带来了很大的效益。今天的内容就是以上内容,最近忙着搞钱,文章很久没更新了,后面会加快补上,咱们下期再见。分享不易,觉得有用的话,帮忙三连一下哦,哈哈!谢过了。