QuestDB使用基于列的存储模型。数据存储在表中,每一列存储在自己的文件和自己的原生格式中。新数据被附加到每个列的底部,以允许按照吸收数据的相同顺序有机地检索数据。
添加模型
QuestDB每次附加一个列,并使用相同的方法更新每个列。列文件的尾部被映射到RAM中的内存页中,列追加实际上是对一个地址的内存写入。一旦耗尽内存页,将取消映射,并映射一个新页。
此方法确保最小的资源流失和一致的追加延迟。

读模型
表列是随机访问的。通过简单的位移位将记录号转换为文件偏移量来读取具有固定大小数据类型的列。然后将列文件中的偏移量转换为延迟映射内存页中的偏移量,从那里读取所需的值。

一致性和持久性
QuestDB通过原子地应用表更新来确保表级别的隔离和一致性。表的更新应用于在原子操作中提交或回滚的表事务的上下文中。与表更新同时进行的查询在某种意义上是一致的,即它们返回的数据要么是提交表事务之前的数据,要么是提交表事务之后的数据——查询结果中不会显示中间未提交的数据。
为了保证原子性,每个表在单独的文件中维护一个 last_committed_record_count 。按照惯例,任何表阅读器读取的记录都不会超过tx_count。这将启用隔离属性:无法读取未提交的数据。由于未提交的数据直接追加到表中,因此事务大小仅受可用磁盘空间的限制。
一旦添加了所有数据,QuestDB commit()将确保在多线程和多进程环境中自动更新tx_count。它这样做是无锁的,以确保对并发读取的影响最小。
存储的数据的一致性保证仅限于QuestDB自动修复异常终止的事务。我们还不支持用户定义的约束、检查和触发器。
数据持久性可以通过commit()来配置,可以选择调用msync()来选择同步或异步IO。

摘要
QuestDB存储模型使用内存映射文件和跨进程原子事务更新作为进程间通信的低开销方法。一个进程提交的数据可以被另一个进程随机地(通过查询)或增量地(作为数据队列)读取。QuestDB提供了多种阅读器实现。
