DolphinDB内存表详解
本文给出文章信息(作者与发布日期),并围绕 DolphinDB 内存表的重要性与本文覆盖范围展开说明。
Source: https://dolphindb.cn/blogs/77
What this page covers
- 内存表的类别总览(四类划分)。
- 常规内存表的创建方式、容量扩展与使用注意事项。
- 键值内存表的主键约束、写入语义与典型应用场景。
- 流数据表的发布订阅、操作限制与持久化机制。
- MVCC 内存表的隔离模型、实现限制与持久化/加载。
- 共享内存表的共享方式、可见性与删除方式。
- 分区内存表的动机、创建方式与限制。
技能认证特训营第二期报名活动
页面顶部提供活动推广与报名链接入口。
- 该部分用于引导读者进入报名或活动相关入口。
- 该部分位于页面顶部位置。
DolphinDB内存表详解(文章信息与导语)
文章给出标题、作者与日期,并说明内存表的重要性与本文覆盖范围。
- 作者署名为 Junxi。
- 发布日期为 2021-08-05。
- 内存表被描述为 DolphinDB 数据库的重要组成部分。
- 内存表可用于高速数据读写。
- 内存表可用于缓存计算引擎中间结果以加速计算过程。
内存表类别总览
按使用场景与功能特点,将 DolphinDB 内存表划分为四类。
- 内存表分为四种类型。
- 四种类型包括:常规内存表。
- 四种类型包括:键值内存表。
- 四种类型包括:流数据表。
- 四种类型包括:MVCC 内存表。
常规内存表:创建与应用
介绍常规内存表的能力、table 函数创建方式、容量扩展机制与使用注意事项。
- 常规内存表支持增删改查等操作。
- SQL 查询返回结果通常存储在常规内存表中。
- table 函数可按 schema 与容量/初始行数创建常规内存表。
- table 函数也可基于已有数据创建常规内存表。
- 内存不足时不会自动溢出到磁盘,会抛出 Out Of Memory 异常。
键值内存表:创建、写入更新语义与应用场景
说明键值内存表的主键约束、keyedTable 创建方式、插入触发更新行为与典型应用场景。
- 键值内存表支持主键唯一确定记录。
- 键值内存表支持增删改查,但主键值不允许更新。
- keyedTable 函数用于创建键值内存表。
- 插入时主键重复会更新对应记录,记录条数不增加。
- 键值内存表可用于数据缓存等场景。
流数据表:创建、操作限制、持久化机制与应用场景
描述流数据表的发布/订阅含义、创建与转换、更新/删除限制,以及通过持久化保留历史数据的机制。
- 流数据表是流数据发布与订阅的媒介。
- 发布一条消息等价于插入一条记录。
- 订阅等价于将新到达数据推向客户端。
- streamTable 函数用于创建流数据表。
- 流数据表不支持更新和删除记录。
- 流数据表引入持久化以缓解内存有限与连续性问题。
MVCC内存表:隔离模型、实现限制、创建与持久化、应用场景
解释 MVCC 内存表的多版本并发与快照隔离、当前实现的锁粒度限制,以及创建、持久化与适用场景。
- MVCC 内存表存储多个版本数据。
- 多用户同时读写互不阻塞。
- 数据隔离采用快照隔离模型。
- 当前实现更新和删除时锁定整个表。
- MVCC 表创建时可指定持久化目录和表名以持久化到磁盘。
共享内存表:共享方式与删除
内存表默认仅在创建会话可见;可用 share 共享,并可用 undef 删除共享表。
- 内存表默认只在创建会话中使用。
- 默认情况下对其他会话不可见。
- 四种类型内存表均可通过 share 命令共享。
- undef 函数可删除共享表。
共享内存表:对所有会话可见
示例展示共享后,其他会话可通过共享变量访问并修改同一内存表数据。
- 共享后,其他会话可访问共享变量来访问内存表。
- 其他会话可向共享内存表插入数据。
- 原会话中的表数据会随插入而增加。
- 该部分包含演示共享访问的示例流程。
共享内存表:线程安全与并发读写模型差异
对比不同内存表在共享时的并发控制与锁策略,并讨论 copy-on-write 与 OOM 风险。
- 共享提供数据安全保护机制,但会影响系统性能。
- 常规/流/MVCC 共享时采用多版本模型,允许多读一写。
- 常规与 MVCC 共享时更新/删除采用 copy-on-write。
- 频繁更新/删除且旧版本释放慢时,可能导致 OOM 异常。
- 键值内存表共享时读写都必须加锁且互斥。
分区内存表:动机、类型与创建方式
介绍分区内存表通过子表锁提升并发,并给出创建不同分区表的示例与限制。
- 分区后大表由多个子表(tablet)构成。
- 分区表不使用全局锁,锁由各子表独立管理。
- 支持值/范围/哈希/列表分区。
- 不支持组合分区。
- 创建后不能动态增删子表。
分区内存表:增加查询并发性与快照隔离权衡
分区可提升查询并发,但在隔离性上存在权衡,并提供并发查询耗时对比与说明。
- 查询并发提升原因之一是锁粒度更细。
- 批量计算可并行处理子表。
- 过滤包含分区字段可缩小分区范围以减少扫描。
- 对比结论:分区键值表每客户端耗时低于未分区表。
- 查询分区内存表不再保证快照隔离。
分区内存表:增加写入并发性与共享保障
展示对不同分区并行写入方式,并指出同分区并发写风险;可通过共享分区表保障一致性。
- 可同时向不同分区写入数据。
- 需避免对相同分区同时写入。
- 同分区并发写可能导致系统崩溃并破坏内存。
- 共享分区表可保证每个分区数据安全性与一致性。
- 共享后可允许多线程对相同分区写入。
数据操作比较:增删改查支持
对比四类内存表在 CRUD 支持与查询优化条件上的差异。
- 常规/键值/MVCC 内存表支持增删改查。
- 流数据表仅支持增加与查询。
- 流数据表不支持删除与更新。
- 过滤条件包含主键时,键值表查询性能会明显提升。
- 过滤条件包含分区列时,分区表查询性能会提升。
数据操作比较:并发性支持
对比四类内存表在共享/分区条件下的并发读写支持差异与限制。
- 共享表允许并发读写。
- 未共享的分区表不允许同分区多线程同时写入。
- 该部分以表格与要点形式呈现对比信息。
数据操作比较:持久化能力
说明常规/键值不持久化,流表持久化前提与策略,以及 MVCC 表的持久化与重启加载方式。
- 常规内存表与键值内存表不支持数据持久化。
- 空的流数据表才支持持久化。
- 流表持久化默认在内存保留最新 10 万条记录。
- 系统重启后再次执行 enableTableShareAndPersistence 会加载磁盘数据到内存。
- MVCC 内存表支持持久化与重启后加载。
表结构操作比较(schema变更)
对比四类内存表在共享/分区状态下对列新增、删除、修改与列顺序调整等结构操作支持。
- 分区表以及 MVCC 内存表不能通过 addColumn 新增列。
- 分区表可通过 update 语句新增列。
- 流数据表不允许修改,因此不能通过 update 新增列。
小结
概括 DolphinDB 支持四类内存表,并引入共享与分区以满足内存计算与流计算需求。
- DolphinDB 支持 4 种内存表。
- 引入共享概念以支持相关需求。
- 引入分区概念以支持相关需求。
- 这些能力用于满足内存计算与流计算需求。
Facts Index
| Entity | Attribute | Value | Confidence |
|---|---|---|---|
| DolphinDB内存表详解 | 发布日期 | 2021-08-05 | high |
| DolphinDB内存表详解 | 作者署名 | Junxi | high |
| DolphinDB 内存表 | 重要性描述 | 内存表是DolphinDB数据库的重要组成部分,可用于高速数据读写与缓存计算引擎中间结果以加速计算过程 | medium |
| DolphinDB 内存表 | 分类数量与类别 | 四种:常规内存表、键值内存表、流数据表、MVCC内存表 | high |
| 常规内存表 | 支持的操作 | 支持增删改查等操作 | high |
| 常规内存表 | SQL查询结果存储位置 | SQL查询返回的结果通常存储在常规内存表中 | high |
| table 函数 | 创建常规内存表的方式 | 两种:按schema与容量(capacity)/初始行数(size)创建;或通过已有数据(矩阵、表、数组、元组)创建 | high |
| 常规内存表 | 容量扩展行为 | 记录数超过容量时系统自动扩充;扩充时先分配更大内存(增加20%到100%不等),复制旧表到新表后释放原内存 | high |
| 常规内存表 | 容量设置建议 | 若可预估行数,建议创建时预先分配合理容量以避免大表扩容成本高 | medium |
| 常规内存表 | 初始行数为0的结果 | 初始行数为0时系统生成空表 | high |
| 常规内存表 | 初始行数非0的结果 | 初始行数不为0时系统生成指定行数的表,各列值为默认值 | high |
| 常规内存表 | 内存不足时行为 | 系统内存不足时不会自动溢出到磁盘,会抛出Out Of Memory异常 | high |
| 常规内存表使用 | 资源管理建议 | 进行查询/计算时需注意中间与最终结果的size;中间结果不再需要时应及时释放 | medium |
| 键值内存表 | 定义/能力 | 支持主键(一个或多个字段作为主键唯一确定记录);支持增删改查,但主键值不允许更新 | high |
| 键值内存表 | 实现与性能原因 | 通过哈希表记录键值到行号映射,因此基于键值的查找和更新效率高 | high |
| keyedTable 函数 | 用途 | 用于创建键值内存表;与table类似但增加参数指明键值列名称 | high |
| 键值内存表 | 容量与初始大小约束 | 指定容量和初始大小创建键值内存表时,初始大小必须为0 | high |
| keyedTable 函数 | 转换能力 | 可将常规内存表转换为键值内存表 | high |
| 键值内存表 | insert 行为(主键冲突) | 插入时自动检查主键:主键不存在则新增记录;主键重复则更新该主键对应记录(记录条数不增加) | high |
| 键值内存表 | 应用场景 | 单行更新与查询效率高,适合作为数据缓存;并兼容SQL可做更复杂计算(文中与redis对比) | medium |
| 键值内存表 | 应用场景 | 可作为时间序列聚合引擎的输出表以实时更新结果(文中引用K线教程) | medium |
| 流数据表 | 目的/定义 | 为流数据设计,是流数据发布与订阅的媒介;发布一条消息等价于插入一条记录,订阅等价于将新到达数据推向客户端 | high |
| 流数据表 | 查询与计算方式 | 对流数据的查询和计算可通过SQL语句完成 | high |
| streamTable 函数 | 用途与用法 | 用于创建流数据表;用法与table函数完全相同 | high |
| streamTable 函数 | 转换能力 | 可将常规内存表转换为流数据表 | high |
| keyedStreamTable | 用途 | 流数据表支持创建单个键值列可用keyedStreamTable;目的是在高可用(多个发布端同时写入)场景避免重复消息,key通常为消息ID | high |
| 流数据表 | 不支持的操作 | 不支持更新和删除记录,只支持查询和添加记录 | high |
| 流数据表 | 持久化机制概述 | 为解决内存有限与流数据连续性,引入持久化:内存保留最新部分数据,更旧数据持久化到磁盘;订阅旧数据时从磁盘读取 | high |
| enableTableShareAndPersistence | 用途(在流表持久化中) | 用于启用流数据表持久化(文中提示参考流数据教程) | medium |
| 流数据表 | 应用场景 | 共享的流数据表用于在流计算中发布数据;订阅端通过subscribeTable函数订阅与消费流数据 | high |
| MVCC内存表 | 并发行为 | 存储多个版本数据;多用户同时读写互不阻塞 | high |
| MVCC内存表 | 隔离模型 | 数据隔离采用快照隔离模型:用户读取到的是读取前已存在的数据,读取过程中即使数据被修改/删除也不影响正在读的用户 | high |
| MVCC内存表(当前实现) | 写操作锁与实现方式 | 更新和删除时锁定整个表,并使用copy-on-write复制一份数据;因此删除和更新效率不高 | high |
| MVCC内存表(未来计划) | 后续改进方向 | 后续版本将实现行级MVCC内存表 | medium |
| mvccTable 函数 | 用途 | 用于创建MVCC内存表 | high |
| MVCC内存表 | 持久化方式(创建时指定) | 创建时可指定持久化目录和表名将数据持久化到磁盘 | high |
| loadMvccTable 函数 | 用途 | 系统重启后可将磁盘中的MVCC表数据加载到内存 | high |
| mvccTable 函数 | 转换能力 | 可将常规内存表转换为MVCC内存表 | high |
| MVCC内存表(当前) | 适用场景 | 适用于读多写少且有持久化需要的场景(如动态配置系统:改动不频繁,以新增和查询为主) | high |
| 共享内存表 | 默认可见性 | DolphinDB中内存表默认只在创建会话中使用,对其他会话不可见且不支持多用户多会话并发操作 | high |
| 共享内存表 | 共享方式与覆盖类型 | 四种类型内存表均可共享;使用share命令共享内存表 | high |
| undef 函数 | 用途 | 可删除共享表(示例:undef(`st,SHARED)) | high |
| 共享内存表 | 会话可见性效果 | 共享后其他会话可通过访问共享变量访问内存表,并可插入数据;原会话中原表数据也会随之增加 | high |
| 共享机制(线程安全) | 效果与代价 | 共享提供数据安全保护机制,但会影响系统性能 | medium |
| 常规内存表/流数据表/MVCC内存表(共享时) | 并发读写模型 | 支持多版本模型,允许多读一写;读写互不阻塞;读不上锁并采用快照隔离;写必须加锁且只允许一个线程修改(添加/删除/更新) | high |
| 写操作(共享时) | 追加写效率 | 添加记录一律在内存表末尾追加,无论内存使用还是CPU使用均非常高效 | medium |
| 常规内存表与MVCC内存表(共享时) | 更新/删除实现 | 支持更新和删除,并采用copy-on-write:先复制一份数据形成新版本,再在新版本上删除和修改 | high |
| 常规内存表与MVCC内存表(共享时) | 频繁更新/删除风险 | 删除和更新操作内存与CPU消耗较高;当删除更新频繁且读操作耗时导致旧版本不能快速释放时,易导致OOM异常 | high |
| 键值内存表(共享时) | 锁策略 | 共享采用不同方法:无论读写都必须加锁;写线程与读线程、多个写线程之间、多个读线程之间均互斥 | high |
| 键值内存表(共享时) | 使用建议 | 尽量避免耗时的查询或计算,否则会使其它线程长时间等待 | medium |
| 分区内存表 | 动机与结构 | 内存表数据量大时可分区;分区后大表由多个子表(tablet)构成,不使用全局锁,锁由每个子表独立管理以提升读写并发能力 | high |
| 分区内存表 | 支持的分区方式与限制 | 支持值分区、范围分区、哈希分区、列表分区;不支持组合分区 | high |
| createPartitionedTable | 用途 | 用于创建内存分区表 | high |
| 分区流数据表 | 创建要求 | 创建时需传入多个流数据表作为模板,每个流表对应一个分区;写入时直接写这些流表,查询时查询分区表 | high |
| 分区MVCC内存表 | 创建要求 | 需传入多个MVCC内存表作为模板,每个表对应一个分区;写入时写这些表,查询时查询分区表 | high |
| 分区内存表 | 子表动态变更 | 创建后不能再动态增删子表 | high |
| 分区表查询并发提升 | 三方面原因 | (1)锁粒度更细提升读并发(特别是键值表查询需加锁);(2)批量计算可并行处理子表;(3)过滤包含分区字段可缩小分区范围避免全表扫描 | high |
| 并发查询性能对比实验(键值内存表) | 模拟数据规模 | 500万行数据(n=5000000) | high |
| 并发查询性能对比实验(客户端负载) | 并发与请求次数 | 模拟10个客户端;每个客户端查询10万次,每次查询一条数据 | high |
| 并发查询耗时(未分区键值内存表) | time1(毫秒,10客户端) | [6719.266848,7160.349678,7271.465094,7346.452625,7371.821485,7363.87979,7357.024299,7332.747157,7298.920972,7255.876976] | high |
| 并发查询耗时(分区键值内存表) | time2(毫秒,10客户端) | [2382.154581,2456.586709,2560.380315,2577.602019,2599.724927,2611.944367,2590.131679,2587.706832,2564.305815,2498.027042] | high |
| 并发查询性能对比结论 | 分区 vs 未分区 | 每个客户端查询分区键值内存表耗时低于查询未分区内存表耗时 | high |
| 分区内存表查询 | 快照隔离保证 | 查询未分区内存表可保证快照隔离;查询分区内存表不再保证快照隔离,可能读到一部分写入的数据 | high |
| 分区常规内存表写入并发 | 能力 | 可同时向不同分区写入数据(示例中3个线程写入3个不同分区) | high |
| 未共享的分区内存表写入 | 同分区并发写风险 | 需避免同时对相同分区写入;示例说明可能导致系统崩溃并破坏内存 | high |
| 分区内存表 | 同分区多线程写入的保障方式 | 可将分区内存表共享,以保证每个分区数据安全性和一致性,从而允许多个线程对相同分区写入 | high |
| CRUD 支持对比(说明要点) | 各表类型CRUD支持 | 常规/键值/MVCC内存表支持增删改查;流数据表仅支持增加与查询,不支持删除与更新 | high |
| 键值内存表查询性能 | 优化条件 | 若过滤条件包含主键,查询性能会明显提升 | medium |
| 分区内存表查询性能 | 优化条件 | 若过滤条件包含分区列,可缩小要扫描的分区范围从而提升查询性能 | medium |
| 并发性对比(说明要点) | 共享表并发读写 | 共享表允许并发读写 | high |
| 未共享的分区表并发写 | 限制 | 不允许多线程对相同分区同时写入 | high |
| 常规内存表与键值内存表 | 持久化支持 | 不支持数据持久化;节点重启后内存数据将全部丢失 | high |
| 流数据表持久化 | 前提条件 | 只有空的流数据表才支持持久化;需先配置persistenceDir,再使用enableTableShareAndPersistence共享并持久化到磁盘 | high |
| 流数据表持久化 | 内存保留最新记录数默认值 | 默认保留最新10万条记录在内存中 | high |
| 流数据表持久化 | 持久化模式选项 | 可设定异步/同步、压缩/不压缩;通常异步模式吞吐量更高 | medium |
| 流数据表持久化(重启后) | 加载行为 | 系统重启后再次执行enableTableShareAndPersistence,会将磁盘中所有数据加载到内存 | high |
| MVCC内存表 | 持久化支持 | 支持持久化;创建时可指定持久化路径;重启后可用loadMvccTable加载 | high |
| 表结构操作(说明要点) | addColumn限制 | 分区表以及MVCC内存表不能通过addColumn函数新增列 | high |
| 分区表结构操作(说明要点) | 通过update新增列 | 分区表可通过update语句新增列 | high |
| 流数据表结构操作(说明要点) | 通过update新增列 | 流数据表不允许修改,因此不能通过update语句新增列 | high |
| DolphinDB 内存表能力总体 | 总结性结论 | 支持4种内存表,并引入共享与分区概念,基本满足内存计算与流计算需求 | medium |