BSON 是什么
MongoDB 作为一款流行的文档数据库,采用 BSON 格式来支持文档模型。
BSON 全称是 Binary JSON,和 JSON 很像,但是采用二进制格式进行存储。相比 JSON 有以下优势:
- 访问速度更快:BSON 会存储 Value 的类型,不需要进行字符串类型到其他类型的转换。
以整型 12345678 为例,JSON 需要将字符串转成整型,而 BSON 中存储了整型类型标志,并用 4 个字节直接存储了整型值。对于 String 类型,会额外存储 String 长度,这样解析操作也会快很多
- 存储空间更低:如 Int32 统一采用 4 字节存储,Long 和 Double 采用 8 字节存储。
还是以整型 12345678 为例,JSON 采用明文存储的方式需要 8 个字节,但是 BSON 对于 Int32 的值统一采用 4 字节存储,Long 和 Double 采用 8 字节存储。 当然这里说存储空间更低也分具体情况,比如对于小整型,BSON 消耗的空间反而更高;
- 数据类型更丰富:BSON 增加了 BinData、TimeStamp、ObjectID、Decimal128 等类型。
JSON | BSON | |
---|---|---|
编码方式 | UTF-8 String | Binary |
数据类型 | String, Boolean, Number, Array | String, Boolean, Number (Integer, Float, Long, Decimal128…), Array, Date, Raw Binary |
可读性 | Human and Machine | Machine Only |
BSON 存储格式
一条最简单的 BSON 文档,从前向后可以拆解成以下几个部分:
- 文档的总长度,占 4 个字节;
- 多个 BSONElement 按顺序排列,每个包含:
- Value 类型(1 字节)
- Key 的 C-String(以
\0
结尾) - Value 的二进制存储(如 Int32 占 4 字节等)
- 文档以
\0
结尾(EOO,End Of Object,1 字节)
常用类型举例
Int 类型:直接存储 4 字节二进制。
Double 类型:占 8 字节,IEEE 754 标准。
String 类型:头部有 4 字节长度,内容以
\0
结尾。
需要注意的是,BSON 有 2 种 String 类型:
1、C-String: 一般用于 Key ,以 ‘\0’ 结尾,不存储长度信息;
2、String: 一般用于 Value,以’\0’ 结尾,头部会存储 4 字节的长度信息;
这样设计的好处是:
1、Key 一般长度较短,可以很快解析。不需要额外的 4 字节的存储开销和解析开销;
2、Value 一般长度较长,通过存储 4 字节的长度信息,可以明显加快解析速度;
嵌套文档:头部有 4 字节长度,内容同普通文档。
嵌套文档和普通文档一样,头部也包含了额外的 4 字节长度空间。比如下面的例子 {“b” : NumberInt(1)} 的存储长度为 12 字节。
数组类型:头部有 4 字节长度,每个元素有下标(‘0’ 开始)。
数组类型头部有 4 个字节存储长度,每个元素都对应有下标,从 ‘0’ 开始递增。
比如下面的例子中,“a.0” 表示第 1 个元素,值为 Double(1), “a.3” 表示第 4 个元素,值为 “4”.
BSON 的解析和封装
解析流程
- 先用小端模式读取头部 4 字节,得到 BSON 文档长度。
- 迭代获取 Value 类型、Key、Value,直到文档结束。
- 参考 MongoDB 代码中的 BSONObj 和 BSONObjIterator。
封装流程
- 通过 BSONObjBuilder 流式生成 BSON 文档。
- 修改字段时,通常会生成新的 BSON 文档。
- 只有不改变二进制结构的更新才支持 UpdateInPlace。
性能测试
BSON 在常用的 Double、Long、String 类型下,长度和编解码性能优于 JSON,但不同场景下差异较大。
1. 存储空间(长度)效率
对于 “长” double/int64 类型,BSON 在空间上,有一定优势。因为 BSON 使用固定 8 字节进行编码。 对于 “短” double/int64 类型,BSON 在空间上,存在劣势。还是因为 BSON 使用固定 8 字节编码的原因。 对于测试使用的 string 类型,BSON 并没有优势。
2. 编码(marshal)效率
对于测试使用的 “长” double 类型和 string 类型, BSON 均有10%-30% 的性能提升。 在 “短” double 类型上,BSON 和 JSON 性能相当。 对于 int64 类型,不管数据的长短,BSON 均有明显的性能下降。需要额外关注,并进一步分析。
3. 解码(unmarshal)效率
BSON 优势非常明显。对于测试使用的 “长” double/int64 类型有 100% 的性能提升,对于 string 类型有 200% 以上的性能提升。 对于 “短” double/int64 类型,也有20% 以上的性能提升。