为什么MapDB的读取性能慢于LMDB与RocksDB?
MapDB单值读取性能弱于LMDB、RocksDB的核心原因
- 底层存储架构的读路径冗余度差异
LMDB采用纯mmap实现的COW B+树,读路径完全零拷贝、无系统调用、无锁,只要目标数据在操作系统页缓存里,直接通过内存指针就能访问,连额外的内存拷贝都不需要;RocksDB的LSM结构虽然固有读放大问题,但针对热数据读路径做了极致裁剪,布隆过滤器、块缓存的逻辑都做了指令级优化,校验、解压等重逻辑只在冷数据读取时触发。
反观MapDB的B-Link树实现,读路径上默认绑定了CRC校验、通用序列化反序列化、版本一致性检查等固定逻辑,哪怕数据已经在内存里,也要走完整的校验、内存拷贝、对象封装流程,热路径上的指令数比另外两款数据库高一个量级。 - 内存模型的额外开销
MapDB在堆内、堆外、mmap三种存储模式之上做了一层统一的抽象封装,哪怕开启mmap模式,读取Value时也必须把数据从堆外/文件映射内存拷贝到Java堆生成对象后才能返回,没有提供零拷贝读取的能力。同时MapDB读路径需要做轻量的版本锁校验,虽然锁开销很低,但和LMDB完全无锁的读逻辑、RocksDB单线程场景下几乎无锁竞争的实现比,还是有固定的性能损耗。 - 默认配置的冗余开销
大部分基准测试如果直接用MapDB的默认配置跑,会带着默认开启的事务日志、页校验、通用序列化器、定期刷盘等非必要逻辑,这些逻辑在单值读场景下都是纯开销。手动关闭事务(transactionDisable())、绕过页头校验(checksumHeaderBypass())、关闭压缩、替换为对应数据类型的专用序列化器后,MapDB的读性能可以比默认配置提升40%左右,但架构层面的固有开销还是存在,追不上前两者的水平。 - 数据布局的缓存友好性差异
76万条数据的测试量级下,LMDB的B+树页是顺序紧凑填充的,数据局部性极强,CPU缓存命中率非常高;RocksDB的SSTable有序排布,块缓存加载的热数据连续度也很高。而MapDB的B树页默认预留了较大比例的空闲空间供后续写入,相同数据量下树高更高,跨页随机访问的概率更大,CPU缓存miss率是另外两款数据库的2-3倍,这部分开销在JMH微基准测试中会被非常明显地放大。
内容的提问来源于stack exchange,提问作者Awdsa
相关产品推荐
相关产品推荐

