跑得动 FlashDB 的板子不一定跑得动 loxdb:两份嵌入式数据库的资源实测与选型
声明: loxdb 是一个开源项目,作者为 Vanderhell;FlashDB 是一个开源项目,作者为 Armink。本文是阅读两个项目源码并在本地完成资源实测后整理的学习笔记,用于理解嵌入式数据库的资源消耗与设计取舍。本文作者不是这两个项目的开发者,未参与任何代码贡献。 文中工程细节与测量数据来自开源代码分析与本地编译结果,不代表项目作者的设计决策。
项目仓库:github.com/Vanderhell/loxdb(可预测内存的三引擎嵌入式数据库);github.com/armink/FlashDB(RT-Thread 生态的极简 KV/TS 数据库)
loxdb 与 FlashDB 都是面向 MCU 的嵌入式数据库。实测(Cortex-M4,-Os,链接裁剪)下,FlashDB 的 KV+TS 占 10.5KB Flash、RAM 约 1KB;loxdb 同功能占 16.7KB,全功能(KV+TS+关系型+WAL)24.3KB,RAM 最少 8.2KB 句柄加可配 arena。loxdb 用多出的 Flash 换 TTL 过期、事务、关系引擎、写入前预检和可观测的崩溃恢复;FlashDB 用极简换来资源效率与多年量产验证。RAM 预算紧张、只需配置存储时选 FlashDB,需要多引擎与可诊断性时选 loxdb。
loxdb 用资源换来的能力
两类库的资源差距来自存储架构。FlashDB 把状态写进 Flash 按需扫描,换取约 1KB 的总 RAM;loxdb 把状态放进预分配 RAM,Flash 只做持久化快照,代价是句柄与 arena 的固定占用。
loxdb 的回报集中在写入前就能感知的五项能力:
- 写入前预检:
lox_preflight()在初始化前验证配置与存储几何,lox_admit_kv_set()在写入前返回本次操作是否会失败,lox_get_pressure()随时查询剩余容量。FlashDB 的扇区 GC 失败只能在事后通过返回值察觉,部分 API 甚至不返回错误。 - TTL 过期:
lox_kv_set()带 ttl 参数,配合lox_kv_purge_expired()清理。FlashDB 需要自己存时间戳、自己写扫描删除逻辑。 - 事务:
lox_txn_begin()到lox_txn_commit()让多个 key 的更新原子生效,断电也不破坏。FlashDB 每个 KV 独立写入,配网参数写到一半掉电会留下半新配置。 - 可观测的崩溃恢复:
lox_stats()暴露recovery_count与last_recovery_status,设备经历过掉电恢复可以被记录用于售后诊断。FlashDB 的状态位翻转同样防掉电,但不会上报恢复事件。 - 关系型引擎与迁移:schema 建表、索引列、
lox_rel_find_by()按列查找;schema 带版本号,on_migrate回调处理固件升级时的结构变更。FlashDB 只有 KV 默认值升级,解决不了表结构变化。
资源占用实测
以下数字来自 arm-none-eabi-gcc 14.3.1 对 Cortex-M4 的 -Os 编译,链接时开启 --gc-sections 裁剪。loxdb 使用官方默认配置(64 键、8 条 TS 流、4 张表);FlashDB 数字包含其仓库自带的 FAL 抽象层(单独编译约 2.3KB),loxdb 不含存储移植层。数字用于说明资源量级,不代表所有芯片和工具链都会得到相同结果。
| 配置 | loxdb | FlashDB | 差距 |
|---|---|---|---|
| KV-only(含断电保护) | 11,109 B(KV+WAL) | 8,400 B(含 FAL) | loxdb 多 3 成 |
| KV + TS | 16,684 B(KV+TS+WAL) | 10,534 B(含 FAL) | loxdb 多 6 成 |
| 全功能 KV+TS+关系型+WAL | 24,243 B | 无对应功能 | 无法直接对比 |
静态 RAM 的构成差异更大:
| 项目 | loxdb | FlashDB |
|---|---|---|
| 库自身静态量 | 128 B | 16 B |
| 用户必须提供的数据结构 | lox_t 句柄 8,200 B、schema 896 B | fdb_kvdb 876 B、fdb_tsdb 100 B |
| 运行期动态内存 | arena(可配 8~64KB) | 无 |
能力对比
| 能力 | loxdb | FlashDB |
|---|---|---|
| KV / TS 存储 | 有 | 有 |
| 关系型表 | 有 | 无 |
| 事务原子提交 | 有 | 无 |
| TTL 过期 | 有 | 无 |
| 写入前预检与容量查询 | 有 | 无 |
| 断电恢复可观测 | 有(恢复计数与状态) | 无(状态位翻转,不上报) |
| 错误码粒度 | 16 类 | 粗粒度,部分 API 无返回 |
| schema 版本迁移 | 有(on_migrate) | 仅 KV 默认值升级 |
| 存储后端可替换 | 有(RAM/FS/裸 Flash) | 绑定 FAL |
| C++ 封装与 JSON 导入导出 | 有 | 无 |
| 线程安全钩子 | 有(可选) | 无(需外部加锁) |
| 代码占用与 RAM | 高 | 极低 |
| 成熟度与量产验证 | 新项目(v1.5.x) | 多年量产 |
选型依据
- RAM 预算 ≥ 32KB,需要多引擎、事务、TTL 或结构化查询,看重运行时可诊断,选 loxdb。
- 8~16KB RAM,只需 KV 配置存储,量产验证优先,选 FlashDB。
- 折中路径:loxdb 支持编译期裁剪(可单独关闭 TS/REL/WAL),KV-only 档约 11KB,仍高于 FlashDB 的 8.4KB。
- 建议按自己的芯片与工具链重测一次。方法可复现:
arm-none-eabi-gcc -Os -ffunction-sections -fdata-sections编译,链接加--gc-sections,用arm-none-eabi-size读 section 尺寸。
loxdb 的工程化优势(预检、自检、统计、可观测恢复)建立在 8KB 以上的 RAM 契约上,这条契约在小内存 MCU 上不成立。选型依据是 RAM 预算落在哪一档;预算允许时,功能清单才参与比较。