PostgreSQL 的 jsonb 是现代数据库领域的一个“杀手级”特性。它的出现让 Postgres 从一个单纯的关系型数据库(RDBMS),摇身一变成为了一个多模数据库(Multi-Model Database)。
简单来说,jsonb 让你可以在关系型数据库里,获得不输给 MongoDB 的文档存储体验,同时还能享受 SQL 的强大功能。
以下是关于 jsonb 的详细解剖及其核心优势分析:
一、 什么是 jsonb?(vs json)
Postgres 有两种 JSON 数据类型:json 和 jsonb。虽然只差一个 "b",但底层天差地别。
-
json(Text-based):- 存储方式:把 JSON 当作纯文本存储。
- 特点:保留原始格式(包括空格、键的顺序、重复键)。
- 缺点:每次查询时,数据库必须实时解析文本,无法建立高效的深层索引。
- 用途:仅用于日志记录,或者你需要严格保留原始 JSON 格式的场景。
-
jsonb(Binary decomposed):- 存储方式:二进制格式。在写入时,PG 会把 JSON 解析并转换成一种树状的二进制结构。
- 特点:
- 写入稍慢(因为有转换开销)。
- 查询极快(不需要重新解析)。
- 不保留格式(去除空格、去重键、不保证键的顺序)。
- 核心能力:支持索引(GIN Index)。这是它能打败竞品的关键。
二、 jsonb 相比竞品(MongoDB, MySQL)的优势
jsonb 的主要竞争对手是 MongoDB(NoSQL 代表)和 MySQL 的 JSON 类型。
1. 对比 MongoDB:ACID 与 复杂查询的胜利
MongoDB 是原生的文档数据库,不仅存 JSON,还处理分片和高并发写入。但在很多业务场景下,Postgres jsonb 是更好的选择:
-
最大的杀手锏:事务 ACID(Atomicity, Consistency, Isolation, Durability)
- 场景:你要在电商系统里下一个订单,同时扣减库存(关系型表)并记录订单快照(JSONB)。
- PG 优势:你可以把
UPDATE inventory和INSERT INTO orders (data)放在同一个事务里。要么全成功,要么全失败。 - MongoDB:虽然现在也支持多文档事务,但性能和复杂度的代价远高于 Postgres。在 Postgres 里这是原生、零成本的。
-
关联查询(JOINs)的能力
- PG 优势:你可以轻松地
JOIN一个关系型表(如 User 表)和一个文档型列(如 Log 表里的jsonb)。 - MongoDB:虽然有
$lookup,但不仅写起来反人类,性能也无法与经过几十年优化的 SQL 优化器相比。
- PG 优势:你可以轻松地
-
运维成本(Stack Simplification)
- 你不需要为了存一点非结构化数据就单独维护一个 MongoDB 集群。“One DB for All” 可以极大地降低运维复杂度。
2. 对比 MySQL JSON:索引与生态的碾压
MySQL 从 5.7 开始支持 JSON,但 Postgres 的 jsonb 在成熟度上依然领先:
-
索引机制(GIN Index)
- Postgres:使用 GIN (Generalized Inverted Index) 索引。你可以对整个 JSON 文档建立索引。
CREATE INDEX ON table USING GIN (data);- 查询
WHERE data @> '{"country": "CN"}'时,它可以直接命中索引,不需要像 MySQL 那样必须为特定的 Key 创建虚拟列(Virtual Columns)或单独索引。
- MySQL:虽然也可以索引,但通常需要通过提取生成的列(Generated Columns)来变相实现,灵活性和直接性不如 PG 的 GIN。
- Postgres:使用 GIN (Generalized Inverted Index) 索引。你可以对整个 JSON 文档建立索引。
-
操作符丰富度
- Postgres 提供了极其丰富的 JSON 操作符:
@>(包含)?(键是否存在)->(获取元素)#-(删除路径)
- 这种语法糖让 SQL 写起来非常简洁。
- Postgres 提供了极其丰富的 JSON 操作符:
三、 jsonb 的核心技术细节:为什么它这么快?
1. GIN 索引 (倒排索引)
这是 jsonb 性能的秘密武器。
假设你有一列 data 存了 { "tags": ["a", "b", "c"], "user": { "id": 1 } }。
当你建立 GIN 索引时,Postgres 会把里面的 Key 和 Value 拆解出来,建立一个倒排映射:
- "tags" -> 指向这一行
- "a" -> 指向这一行
- "b" -> 指向这一行
当你查询 WHERE data @> '{"tags": ["a"]}' 时,PG 不需要扫描整表,而是像搜索引擎查关键字一样,直接定位到包含 "a" 的行。这让千万级数据量的 JSON 查询可以在毫秒级完成。
2. jsonb_path_ops 优化
如果你只关心“包含关系”(比如查某个 Key 等于某个 Value),可以使用 jsonb_path_ops 索引类,它的体积比默认索引更小,速度更快。
四、 什么时候该用 jsonb?(最佳实践)
虽然 jsonb 很强,但不要把它当成偷懒的工具。不要把所有数据都塞进一个 JSON 字段里,那样你就失去了 SQL 强类型的优势。
推荐场景(Hybrid 混合模式):
- 稀疏属性 / EAV 模式的替代:
- 商品系统:不同的商品有不同的属性(衣服有颜色、尺码;电脑有 CPU、内存)。以前需要建立复杂的 EAV 表,现在直接一个
attributes字段存jsonb。
- 商品系统:不同的商品有不同的属性(衣服有颜色、尺码;电脑有 CPU、内存)。以前需要建立复杂的 EAV 表,现在直接一个
- 不确定的外部数据:
- Webhook 接收:当你对接第三方支付或 API 时,对方返回的 JSON 结构可能会变。直接存
jsonb,后续再根据需要提取。
- Webhook 接收:当你对接第三方支付或 API 时,对方返回的 JSON 结构可能会变。直接存
- 配置项 / Metadata:
- 用户的个性化设置(前端布局、通知开关),这些结构经常变,不适合频繁改表结构(DDL)。
不推荐场景:
- 高频更新的字段:
jsonb是作为一个整体存储的。如果你只修改 JSON 里的一小部分(例如count++),PG 实际上是把整个旧 JSON 读出来,修改后,写一个新的 JSON 进去。这会产生大量的 WAL 日志和 IO 开销。如果某个字段频繁更新,请把它提出来做成独立的列。
- 核心业务外键:
- 尽量不要在
jsonb内部存user_id然后指望用它去 JOIN。虽然技术上可行,但无法建立物理外键约束(Foreign Key Constraint),数据一致性难以保证。
- 尽量不要在
总结
PostgreSQL 的 jsonb 是目前关系型数据库中对 JSON 支持最完美、性能最强悍的实现。
- 相比 MongoDB:它赢在事务一致性(ACID)、SQL 强大的分析能力以及运维的统一性。
- 相比 MySQL:它赢在 GIN 索引的灵活性和对非结构化数据查询的极致优化。
如果你正在构建一个既需要事务安全,又需要灵活数据结构的系统(如 SaaS 平台、物联网后台、电商系统),PostgreSQL + jsonb (混合模式) 是目前的“版本答案”。