BSON 是什么
1. BSON vs JSON#
BSON(Binary JSON)与 JSON 类似,但以二进制形式存储, MongoDB 使用 BSON 存储文档,因为:
- 高效性:二进制格式减少存储空间和解析时间, 快速序列化和反序列化
- 丰富的数据类型:支持 MongoDB 特有的类型(如 ObjectId 用于唯一标识)
在 MongoDB 官网看到这个表:
JSON | BSON | |
---|---|---|
Encoding | UTF-8 string | Binary |
Data Support | String, boolean, number, array, object, null | String, boolean, number (integer, float, long, decimal128…), array, null, date, BinData |
Readability | Human and machine | Machine only |
看到上面这个表不仅有些疑惑, UTF-8 不也是把字符串编码成二进制码, 不也是 Binary 吗? 为什么说 JSON 编码方式是 UTF-8 string, 而 BSON 的编码就是 Binary?
UTF-8 不是 Binary, 因为他就是简单的把 字符 和 二进制数 进行简单的一一映射, 而 BSON 的 Binary 是指, 在存储到内存的时候, 有固定的格式, 比如第一个字节表示数据长度, 第二个字节表示类型信息 等等, 以存储 {"age": 42}
为例:
JSON(UTF-8):
- 文本表示:
{"age": 42}
- UTF-8 编码后:字节序列可能是
[0x7B, 0x22, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x34, 0x32, 0x7D]
- 解析:先将字节解码为 UTF-8 字符,再按 JSON 语法解析为键值对
BSON:
- 二进制表示:可能是一个结构化的字节序列,比如
[文档长度][字段类型:字符串][字段名:age][类型:整数][值:0x0000002A]
- 解析:直接读取字节,按照 BSON 协议提取字段名、类型和值,无需文本解码
UTF-8 的“二进制”只是字符的字节编码, 逻辑上是文本, 映射简单且无结构;BSON 的“二进制”是有固定格式的结构化数据,包含类型和长度等元信息, 直接按二进制协议处理, 这种区别决定了 JSON(基于 UTF-8)更适合人类可读场景, 而 BSON 更适合高效存储和传输, 如果不高效, 为啥还要额外的存储类型, 长度等元数据呢?
2. 序列化和反序列化#
- 序列化 是将内存中的对象转换为可存储或传输的格式
- 反序列化 是将存储的格式转换回内存中的数据结构
3. 为什么 BSON 序列化/反序列化更快?#
JSON 的问题
- JSON 是纯文本格式, 序列化时需要将数据转换为字符串(比如数字 25 变成 “25”,加上引号、括号等)
- 反序列化时, 程序需要逐字符解析文本,检查语法(比如
{
、"
、,
), 然后将字符串转换回正确的数据类型("25"
变回数字25
) - 这个过程涉及大量字符串操作,比较慢,尤其在处理大数据量时
BSON 的优势
- BSON 是二进制格式,数据直接以字节形式存储,接近计算机内存中的表示方式
- 序列化时, BSON 直接将数据(如数字、日期)按固定字节格式写入, 无需转换为文本
- 反序列化时, 程序读取固定长度的字节, 直接还原为内存中的数据类型, 无需复杂的文本解析
4. BSON 序列化过程#
{
"name": "Alice",
"age": 25
}
1. 确定文档结构
- MongoDB 客户端分析对象,识别字段名(name, age)和值(“Alice”, 25)以及类型(字符串、整数)
2. 分配二进制空间
- BSON 为整个文档分配一个固定长度的二进制缓冲区
- 文档开头记录总长度(字节数),方便快速读取
3. 编码字段, 每个字段按以下结构编码
- 类型标识:1 字节,表示数据类型(比如 \x02 表示字符串,\x10 表示 32 位整数)
- 字段名:以空字节(\x00)终止的字符串
- 值:根据类型编码(字符串带长度前缀,整数直接写字节)
示例
-
name: “Alice”
-
类型:\x02(字符串)
-
字段名:“name\x00”(5 字节)
-
值:"\x06\x00\x00\x00Alice\x00"
-
age: 25
-
类型:\x10(32 位整数)
-
字段名:“age\x00”(4 字节)
-
值:"\x19\x00\x00\x00"(4 字节,25 的二进制表示)
4. 写入文档
所有字段按顺序写入缓冲区,文档以 \x00 结尾, 最终 BSON 数据(简化表示)
\x16\x00\x00\x00 // 文档总长度(22 字节)
\x02name\x00\x06\x00\x00\x00Alice\x00 // name="Alice"
\x10age\x00\x19\x00\x00\x00 // age=25
\x00 // 文档结束
MongoDB 如何利用 BSON 元数据查询单个字段
在上面的例子中,BSON 数据是:
\x16\x00\x00\x00 // 文档总长度(22 字节) \x02name\x00\x06\x00\x00\x00Alice\x00 // name="Alice" \x10age\x00\x19\x00\x00\x00 // age=25 \x00 // 文档结束
关键元数据:
- 文档总长度(开头 4 字节):告诉 MongoDB 整个文档有多大
- 字段类型(如 \x02, \x10):表示字段是字符串、整数等
- 字段名(如 “name\x00”):标识字段
- 值长度(如 \x06\x00\x00\x00):对于字符串等变长数据,标明值的字节数
这些元数据让 MongoDB 可以快速定位字段,而无需读取无关部分