【想法】基于精准增量数据的计算。

Viewed 40

背景

基于Doris做分钟近实时统计,是一种典型的数仓分层,我们只需要关注ods -> dwd这个链路, 因为相比于聚合计算。 dwd层一般是需要打宽的,打宽就是一个多表join的过程,对于分布式数据库来说, join的优化是一个痛点。 在使用Doris数仓近实时统计中是资源消耗(CPU,内存,磁盘IO)较大的一个点。

现状

Doris做分钟级近实时打宽,肯定是只能计算增量数据的,因此sql逻辑中一般会有一个基于时间增量限定条件。逻辑表示如下:

select * from log_action la where updateTime >= date_sub(now(), interval 5 MINUTE)

日志以时间为分割, 通过当前时间往前回溯几分钟来确保所有的增量数据都会被涵盖到,保证ods层数据不丢一条的进入到dwd层。

现状问题

1: 理论上如果调度周期是1分钟,则增量数据也是1分钟的数据,但为了保证数据在调度失败若干次后, 依然能不丢数据的进入到下一层, 因此往前回溯的时间一般要大于调度周期, 且为若干倍数。 这就带来几倍的资源消耗。 对整体的集群利用率不利。
2: 这种思路依然不能保证在调度失败好多次后不漏数据。并不是绝对可靠的方案。

思路1

将ods层的增量数据列,拉到dwd层中,并用dwd层的一列存储ods层的增量分割列。 然后用dwd这一列的max来作为ods层的增量列的分割锚点。逻辑如下:

select * from ods表  where  增量分割列 >= (select max(dwd表中从ods层同步过来的增量分割列) from dwd表) sub

上面的思路有两个问题:
1: 优化器可能有效率问题,参考帖子https://ask.selectdb.com/questions/D1ad/E11e。 主要是【数据操作】目录的说法。
2: dwd层一般是unique模型(业务要保证唯一),在unique模型的非索引列计算max最不高效。@zclllyybb的说法。
3: 就算上述可行,dwd层需要存整个增量列。其实只有一个max值是需要关注的,用来作为增量限定的分割锚点。

思路2

以下的内容是doris没有的机制。就是实现上述思路一种设计思路。 (瞎编的)。
利用sql hint语句,记录当前批次插入的某一列的最大值。存储到某个位置, 然后作为增量限定的锚点。 作为where后的分割条件。

insert into table target_table
slect
 /*+ SET_FIELD_NAME_MAX_VALUE("key_001",id_field) */
id_field,   -- 增量限定分割列  
*
from 
source_table 
where
id_field  > GET_FIELD_NAME_MAX_VALUE("key_001")

注意:
1:务必根据导入事务判断,只有导入成功时才会更新锚点值。
2:GET_FIELD_NAME_MAX_VALUE应该是一个函数,可以随时查询当前的值。

select GET_FIELD_NAME_MAX_VALUE("key_001");

3: 同样, 也应该可以通过set的方式重置对应的值。 通过手动可提供一定的灵活性。
4: 第3条也可以做一个点火机制。 首次启动之前没有对应的锚点值。需要手动设置。
5: 就是参考消息队列的group_id的机制。
6: 一般来讲,对应的增量数据分割列最合适是增量id列或递增时间列(业务保证递增或数据库自动产生的当前时间)。 但实际中,保证灵活性,可以不限定列类型。 由使用人员保证。机制上只需要记录当前批次的max就可以了。

1 Answers

实现设计可以不同。但作为实时分析型数据库, 精准定义增量数据的需求一定是存在的。