第三部分:NoSQL 能力扩展实战

第十章 JSON 与 JSONB 数据类型深度解析

第一节 JSON vs. JSONB 的区别

目标:深入理解 PostgreSQL 提供的两种 JSON 数据类型——JSONJSONB——的核心区别,并明确在何种场景下应该选择哪一种。

PostgreSQL 对 NoSQL 的支持,最核心的体现就是它对 JSON 文档的强大原生支持。从 9.2 版本引入 JSON 类型,到 9.4 版本引入更强大的 JSONB 类型,PostgreSQL 已经成为处理半结构化数据的领先者。

然而,许多初学者会对这两种看起来相似的类型感到困惑。理解它们的区别,是高效使用 PostgreSQL JSON 功能的第一步。


核心区别:存储方式

JSONJSONB 的最大区别在于它们的存储方式

JSON 类型

  • 存储方式原文存储(Raw Text Storage)
  • 工作原理:当你向一个 JSON 类型的字段插入数据时,PostgreSQL 几乎是原封不动地存储你传入的文本字符串。它只会做一个简单的合法性校验,确保它是一个有效的 JSON 格式。
  • 特点
    • 保留所有原始格式,包括空格缩进对象中键的顺序
    • 保留对象中重复的键

示例:

1
2
3
4
5
6
-- 注意多余的空格和重复的 "a" 键
SELECT '{"a": 1, "b": 2,   "a": 3}'::json;
--         json
-----------------------------
-- {"a": 1, "b": 2,   "a": 3}
--(1 row)

结果与输入完全相同。

JSONB 类型

  • 存储方式二进制格式存储(Binary Format Storage)
  • 工作原理:当你向一个 JSONB 类型的字段插入数据时,PostgreSQL 会先将输入的文本解析,然后转换成一种高度优化的二进制格式进行存储。
  • 特点
    • 不保留多余的空格和缩进。
    • 不保留对象中键的原始顺序(通常会按一定规则重排)。
    • 不保留重复的键,只会保留最后一个遇到的值。

示例:

1
2
3
4
5
SELECT '{"a": 1, "b": 2,   "a": 3}'::jsonb;
--       jsonb
--------------------
-- {"a": 3, "b": 2}
--(1 row)

结果被“清理”了:空格消失了,键的顺序可能变了,重复的 “a” 键只留下了最后一个值 3


性能对比

存储方式的差异直接导致了性能上的巨大不同。

操作JSONJSONB解释
写入性能更快稍慢JSON 只需存储文本,而 JSONB 需要解析和转换,有额外的 CPU 开销。
读取/处理性能较慢快得多JSON 数据在每次查询时都需要被重新解析。而 JSONB 以二进制格式存储,无需再次解析,可以直接进行操作。
索引支持有限非常强大JSONB 支持 GIN(通用倒排索引),可以极大地加速对键、值或路径的查询。这是 JSONB 最核心的优势。

结论:我应该用哪个?

在绝大多数情况下,你应该总是选择 JSONB

选择 JSONB 的理由:

  • 查询性能:二进制格式和强大的 GIN 索引支持,使得 JSONB 在数据查询和处理上远胜于 JSON
  • 功能更强:许多高级的 JSON 操作符和函数只支持 JSONB
  • 数据规范:自动去重和格式化,有助于保持数据的一致性。

选择 JSON 的唯一理由:

  • 保留原始格式:如果你的应用场景严格要求保留输入的 JSON 字符串的每一个字节,包括空格、缩进和重复的键(例如,某些需要进行数字签名的日志系统),那么 JSON 是你唯一的选择。
  • 写入密集型应用:如果你的应用主要是海量写入 JSON 数据,而几乎不做任何查询,那么 JSON 的写入性能优势可能会有一点价值。但在大多数真实场景中,数据终究是要被查询的。

总结成一句话:除非你有非常特殊的理由需要保留 JSON 的原始文本格式,否则请始终使用 JSONB 它是 PostgreSQL NoSQL 能力的基石。在本书后续的章节中,如无特别说明,我们提到的 JSON 功能都将基于 JSONB 类型。