下述脚本以创建一个组合分区的数据库为例,和 OLAP 引擎创库时的区别仅在于 engine 设置不同:
db1 = database(, VALUE, 2025.01.01..2021.01.01) db2 = database(, HASH, [SYMBOL, 100]) db = database(directory=dbName, partitionType=COMPO, partitionScheme=[db1, db2], engine="TSDB")
库表对应关系: 设计分布式数据库时,若存储的是分布式表,推荐一库一表,因为对于不同的表按照同一分区方案进行分区,可能造成每个分区的数据量不合理;若存储的是维度表,推荐一库多表,集中管理,因为维度表只有一个分区,且一次加载常驻内存。
分区设计:
TSDB 引擎单个分区推荐大小: 400MB - 1GB(压缩前)
分布式查询按照分区加载数据进行并行计算(包括查询、删除、修改等操作),若分区粒度过大,可能会造成内存不足、查询并行度降低、更新删除效率降低等问题;若分区粒度过小,可能会产生大量子任务增加节点负荷、大量小文件📄独写增加系统负荷、控制节点元数据爆炸等问题。
分区设计步骤:
以推荐大小作为参照,先根据表中的记录数和每个字段的大小估算数据量,再根据分区方案计算的分区数(如天+股票HASH10 的组合分区,可以按天数 * 10),通过数据量/分区数计算得到每个分区的大小。
若分区粒度不合理,调整分区粒度可以参考以下方案:
粒度过小:若采用了值分区可以考虑改成范围分区,例如按天改成按月;若采用了 HASH 分区,可以考虑改小 HASH 分区数。
粒度过大:若采用了范围分区可以考虑改成值分区,例如按年改成按月;若采用了 HASH 分区,可以考虑改大 HASH 分区数;若是一级分区,可以考虑用组合分区,此时新增一级通常是 HASH 分区,例按天单分区,粒度过大,考虑二级按股票代码 HASH 分区。
合理设置分区至关重要,如需了解详细的分区机制和如何设计合理的分区,可参见 数据库分区
是否允许并发写入同一分区:
此外,为了支持用户多线程能够并发写数据且不会因写入分区冲突而失败,DolphinDB 在创建数据库时支持了一个特殊的配置参数 atomic(该参数是 OLAP 和 TSDB 引擎共有参数):
默认为 ‘TRANS',即不允许并发写入同一个 CHUNK 分区;
设置为 ‘CHUNK',则允许多线程并发写入同一分区。系统内部仍会串行执行写入任务,当一个线程正在写入某个分区时,其他写入该分区的线程检测到冲突会不断尝试重新写入。尝试 250 次(每次尝试间隔时间会随着尝试次数增加而增加,上限是 1s,整个尝试过程约持续 5 分钟)后仍然无法写入,则会写入失败。atomic='CHUNK' 配置可能会破坏事务的原子性,因为若某线程冲突重试达到上限后仍失败,则该部分数据将会丢失,需要谨慎设置。
实际场景下,若设置为 'CHUNK' 发生数据丢失,用户可能难以定位到具体的分区,针对该场景有几个较推荐的方案:
使用 tableInsert 写入,该函数会返回写入数据的记录数,根据记录数可以定位到写入失败的线程任务,若线程涉及的分区没有重叠,可以删除相关分区数据后重新写入。
若使用 TSDB 引擎,且去重策略设置为了 FIRST 或者 LAST,则直接重复提交写入失败的线程任务,系统会进行去重,查询时不会读出重复数据。不适用于去重策略为 ALL 的场景,若为 ALL,则参照方案 1。