数据模型

存储模型

DolphinDB采用数据分区技术,按照一定的规则将大规模数据集水平分区,每个分区内的数据采用列式存储。

1.30.16 和 2.00.4 版本后,DolphinDB 开始支持数据表级别的分区,同时写入同一数据库分区的不同数据表不会再冲突。

下面通过一个例子直观地解释DolphinDB的存储模型。首先,创建数据库和表:

$ db=database("dfs://db1", VALUE, 1 2 3 4)
$ id=take(1..4, 1000)
$ x=take(1.0, 1000)
$ t=table(id, x)
$ pt=db.createPartitionedTable(t,`pt,`id)
$ pt.append!(t);

上例的表pt是根据id列的值来划分分区的。id=1的记录会保存到同一个分区,id=2的记录会保存至另一个分区,依此类推。由于该表仅有两列,其在每个分区的数据为两个列文件id.col和x.col。如果副本为2,那么表pt一共有2*4*2=16个列文件。

除了上例使用的值分区外,DolphinDB还支持范围分区、哈希分区、值分区、列表分区和组合分区,用户可以根据业务特点对数据进行均匀分割。具体请参考 创建数据库和表 一节。

数据压缩

DolphinDB支持无损压缩,采用兼顾压缩速度和压缩率的LZ4压缩算法。压缩率与数据重复频率有关,若同一列中的重复项越多,压缩率就会越高。对金融数据,磁盘数据的压缩率一般可达到20%到25%左右。DolphinDB采用增量压缩策略,每次只对新增数据进行压缩,因此批量写入有助于提升压缩效果。若每次仅写入一行记录,且cache engine未开启,则存于磁盘的数据并未进行压缩。

读取数据时,系统从磁盘读取需要的列,解压后加载到内存。

数据写入

现代计算机操作系统为了提升I/O性能,都会提供页面缓冲。当数据写入文件时,并不是直接写入到磁盘,而是写入操作系统的缓冲页面中。如果操作系统崩溃或掉电,可能会导致数据丢失。DolphinDB对数据库log(包括redo log、undo log和元数据的edit log)的写入提供了两种策略:一种是在每次写入后强制刷入磁盘;另外一种是每次写入后不强制刷入磁盘,由操作系统决定何时更新到磁盘。强制刷盘策略保证了数据的安全,但是会降低数据库的写入性能。在实践中,一种既经济又能提升性能的策略是将数据库log写入容量较小但性能较高的SSD盘,将海量数据写入容量大但性能较低的HDD盘。默认情况下,DolphinDB不采取强制刷盘策略,如果实际的应用场景对数据的安全和可靠性要求较高,可以通过将配置参数dataSync的值设置为1来启用强制刷盘策略。

虽然分区数据写入到磁盘文件时不需要强制刷盘,但是每次小批量的写入仍然会影响磁盘I/O性能,也会影响数据压缩效果。为此,DolphinDB提供了分区数据写入缓存的功能,由配置参数chunkCacheEngineMemSize指定。写入缓存功能必须与强制刷盘策略一起使用。当缓存中的数据量达到阈值时,系统才会将数据写入磁盘,这样避免了频繁的磁盘操作。

DolphinDB主要是为海量结构化数据的存储、检索、分析和计算设计的,目前不支持交易型场景需要的单条记录修改和删除功能。如果用户需要删除或修改单条记录,只能以分区为单位进行删除和修改。例如,在上例的数据库采用了基于id的值分区。只能删除表pt中所有id=1的数据,而不能删除某一条id=1的数据;如果需要修改某条id=1的数据,需要把所有id=1的数据加载到内存中进行修改,并删除原来所有id=1的数据,修改完成后需要把所有id=1的数据添加到表pt中。具体请参考 删除分区