各位程序员大佬,在线求助一个代码设计问题! 大数据,对某个时间范围的历史数据,执行删除+插入操作的最佳实践是什么??我用的 ClickHouse,本质上是事务问题。目前有 2 个疑问请教大家,附上我的思考过程......感觉我要提桶跑路了

2022-10-15 23:20:12 +08:00
 0x0208v0

如题,各位,之前用的是 PostgreSQL ,现在迁移到 ClickHouse ,请教关于 ClickHouse 的 2 个问题:

我们有一些数据从第三方 API 来,表示某天某个国家某个 APP 的点击数和花了多少钱,

数据表的字段大概这样:
date: 数据时间(主键)
coutry: 国家 (主键)
app: 应用名(主键)
clicks: 点击数 (整数
spends: 花费的金额 (浮点数)

现在的需求是这样:

第三方 API 提供的历史数据可能有变化,需要及时处理,以便于报表能够及时更新
比如:
今天是 2022 年 10 月 15 日,但 2022 年 1 月 1 日~2022 年 1 月 10 日的历史数据需要更新
那应该先删除 2022 年 1 月 1 日~2022 年 1 月 10 日的历史数据,再插入该时间范围新的数据

该时间范围数据更新操作,产生了下面三种情况:

  1. 对于 date+country+app 维度,历史数据和新数据都有,相当于覆盖了历史数据
  2. 对于 date+country+app 维度,历史数据没有,相当于新加了数据
  3. 对于 date+country+app 维度,历史数据有,但新数据没有,相当于删了该数据

有两个问题想要请教大家:

  1. 对于这种场景,ClickHouse 有没有什么最佳实践?
    我通过互联网了解到,只能先删除,然后轮询数据库,等删除结束了再插入
  2. 基于问题 1 ,我知道 ClickHouse 没有事务,并且删除和插入都是异步的,也都不是原子的,
    假如某个时间范围的数据需要更新,并且有多个并行任务,
    同时对 该时间范围 的历史数据,执行删除+插入的动作,
    ClickHouse 能够保证数据最终正确吗? (保证最后一个任务的删除+插入数据是完整的)
    这种情况业务上不想加锁该咋办?(业务原因确实会遇到这样的问题)

我的思考过程:

方案 1 用版本号解决,只插入数据,每批新数据都是比旧数据的版本号大

该方案有问题,比如数据时间范围是 2022 年 1 月~2022 年 12 月,版本号是 1
这时候删除+插入 2022 年 6 月的数据,版本号是 2 如果我按照 2022 年 1 月到 2022 年 12 月聚合数据,我得咋查出来啊?? 再就是没办法表示已经删除的数据,除非增加一列,is_deleted ,问题是我怎么查询。。。

方案 2 在数据表设计一个更新时间字段,类似版本号 V2 版本

该方案的问题在于,删除数据是要删除比当前时间小的数据,那么问题来了 假如有这种情况: 任务 1 一共 100 条数据,插入了 50 条还没插完,这时候任务 2 开始执行了 因为任务 1 的更新时间要小于任务 2 ,任务 2 会先执行删除操作,所以会不会出现删不全的数据?

1465 次点击
所在节点    程序员
5 条回复
yongjing
2022-10-16 00:13:29 +08:00
没有 clickhouse 使用经验,不过大数据仓库都类似。
大概搜了一下,针对前两种情况,表引擎采用 ReplacingMergeTree ,做一次 insert 就好。
第三种情况,查不到的数据,如果不要求回溯,从表里直接删除就好。加版本号方案也没问题,自己权衡吧。
reter
2022-10-16 10:20:00 +08:00
如果数据时间的精度是日,那就比较好办, 如 #1 所说,使用 ReplacingMergeTree

把所有操作都转换成插入操作, 例如,删除操作可以转换为插入 clicks 和 spends 字段都为 0 的记录, 或者你想要的其他字段,用于覆盖旧记录。

用时间戳做版本号 ver (不要程序产生,用 sql 产生时间戳,为了保持 ver 近似单调递增)

查询时候可以认为, 主键相同的所有记录中,ver 最大的记录才是最终的记录:SELECT * FROM table1 GROUP BY 主键 ORDER BY ver LIMIT 1
0x0208v0
2022-10-16 21:45:32 +08:00
@yongjing
@reter
谢谢,我仔细想一想
Maxwe11
2022-10-17 00:37:01 +08:00
1 、至少是我个人没有看到过类似的最佳实践;
2 、clickhouse 是 olap 统计分析数据库,它只统计分析但是并不考虑数据本身的过多变化;
3 、参考 #2 楼朋友的描述,如果 clickhouse 不变,那么就增加一列 insert_time ,不用去刻意删除历史数据,统计的时候以最新 inserttime 为准,就是同时间周期的 max(insert_time)数据的聚合。
0x0208v0
2022-10-17 10:11:50 +08:00
@Maxwe11 仔细想了一下,打个比方:对于 date+country+app 维度,如果按照某个时间范围更新数据,有一种情况是历史数据有,但新数据没有,相当于删了该数据,查询也不应该查出来,增加版本号没办法避免这种情况

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/887210

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX