doris数据批量写入数据存在执行更新不存在执行插入

doris的更新特指对于unique类型的表,对于这种类型的表,如果insert的记录与已有的记录的unique key相同,也相当与update。

doris无论是什么类型的表,都是追加方式修改、增加数据的。

一个insert或update语句就是一次导出,会被一个事务包起来保护,也会生成一个segment文件,无论什么类型的表,无论一个insert插入多么少的数据,都会新增一个segment文件,而不是在已有的segment文件中增加数据。

就是说如果频繁执行小数据量的insert就会产生非常多的很小的segment文件。

可见doris的设计是为了一次大批量的导入的,而多次小批量导入效率是不高的。

doris BE的update流程调试起来比较麻烦,是因为线程较多,许多调用不是一个线程完成,而且多个线程合作完成,调用栈是一个线程的,但是许多调用函数不在一个线程中执行。

我对doris批量更新原理的理解如下:

1、只有 unique 类型的表支持更新操作,insert 和 update 底层本质上是一样的,insert 时 unique key 冲突时,就是update,本质上doris只有导入和查询两种操作。

2、更新操作,底层实现,就是先把新数据生成并写入新的segment文件,旧数据的segment文件不会修改,但是其中被更新的记录会被标记删除,每个segment有一个deletebitmap对象标记哪些记录被删除,deletebitmap不存储在segment文件中,而是存储在同一个BE节点的rocksdb中,这是个内嵌在BE代码中的key-value数据库,可见,更新时,旧的数据文件不会被修改,只是增加新的segment文件和deletebitmap信息,效率是很高的。

3、读取时,参考每个segment的deletebitmap,判断记录被删除则忽略,如果同一个unique key的记录被多次更新,每次更新都会生成不同的segment和对应的deletebitmap,读取时都要参考(称为merge操作),最终返回的是最后一次更新的数据。

4、一条insert或update语句算是一次导入,即使只包括一条记录,也会生成一个segment文件并写到磁盘,并且之后不会修改或向其中追加数据,下一次insert或update会创建新的segment文件。可见,doris是为了一次大批量的导入/更新设计的,小批量多次的导入(insert/update)会产生大量的小segment文件,效率较低。

5、BE内有线程会定期做 compaction,把若干小的segment文件(属于同一个tablet)合并成一个大的,并且生成新的segment时,物理删除之前被标记删除的行数据,同时删除rocksdb中对应的deletebitmap,以后查询时要做的工作就少多了。

6、有上面的认知可以看到,doris的批量更新操作就是导入操作,效率与导入操作差不多,只是更新时多了查询就数据和记录detebitmap操作,并且把一些垃圾回收工作推后,交给了compaction,这降低了写入的工作量,提高了写入的速度,对读取速度影响也比较小。

7、doris操作写入数据时当字段长度不够时,不会报错,但是数据不会写入数据库
 

你可能感兴趣的:(数据库,java,oracle)