------ 为什么 99% 的场景使用 JSONB?
摘要: 随着 PostgreSQL 成为新一代"全能型数据库",JSON 支持也让它具备了替代 MongoDB 的能力。但在建表时,你是否也纠结过------字段到底该用
json,还是jsonb?两者虽然都能存 JSON,但底层结构、性能表现、索引能力却完全不同。 选错类型,查询性能可能慢几十倍。 本文将从底层机制、性能、索引、应用场景和 Spring Boot 实战全面解析两者的差异,并给出最稳的选型建议。
01|为什么 PostgreSQL 有两种 JSON?
不同于 MySQL,PostgreSQL 提供:
- **
json**:文本 JSON - **
jsonb**:二进制 JSON(推荐)
它们都能存储合法 JSON,但核心目标完全不同。
一句话总结:
json:原样存储,格式完全保留jsonb:性能与索引优先,结构化存储
02|JSON vs JSONB:底层差异
🔹 JSON:只是"被验证过的字符串"
特点:
- 按文本原样存储(空格、换行、缩进都会保留)
- 保留键顺序、保留重复键
- 读取时必须重新解析 → 查询性能很差
适合:只保存不查询的原始报文、审计日志。
🔹 JSONB:结构化的二进制存储(性能王者)
特点:
- 转为二进制结构后存储(紧凑占用更小)
- 自动去重键(只保留最后一个)
- 键顺序会被重新排序
- 支持索引(GIN)
- 查询无需解析 → 非常快
查询性能可比 JSON 快数十倍。
03|一张表看懂差别
| 维度 | JSON | JSONB(推荐) |
|---|---|---|
| 写入速度 | 快 | 稍慢 |
| 读取速度 | ❌ 慢 | ✔ 非常快 |
| 查询能力 | 弱 | ✔ 强 |
| 是否支持 GIN 索引 | ❌ 否 | ✔ 是 |
| 空间占用 | 大 | 小 |
| 支持局部更新 | 较弱 | ✔ 强大(jsonb_set) |
| 保留格式 | ✔ 完整保留 | ❌ 不保留 |
如果你需要查询 JSON 内容 → 必须使用 JSONB。
04|什么时候应该用 JSON?(非常少)
必须同时满足:
- 你不会查询 JSON 内部字段;
- 你需要保留原始格式(顺序、空格、换行);
- 你非常在意写入速度;
典型场景:
- 原始日志存档
- 审计数据快照
- 协议报文的字节级保留
05|什么时候应该用 JSONB?(>99% 的业务)
出现以下任意一点 → 选 JSONB:
- 需要查询 JSON 内部字段
- 需要索引内部字段
- JSON 内容会变化
- 需要局部更新某个字段
- 典型半结构化数据
常见业务:
- 即时通讯消息体(读取状态、上传状态等)
- 电商商品属性(颜色、规格等)
- SaaS 动态设置(用户配置项)
- IoT 设备上报数据
06|实战:PostgreSQL 表与索引
🔹 建表推荐:
CREATE TABLE wx_message (
id BIGINT PRIMARY KEY,
payload JSONB
);
🔹 GIN 索引(性能飞升关键)
CREATE INDEX idx_wx_message_payload
ON wx_message
USING GIN (payload);
没有 GIN 索引,JSONB 实力只发挥一半。
07|Spring Boot / Hibernate 最佳实践
🔹 Entity 映射
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb")
private String payload;
为什么用 String?
- 避免复杂的 JSON 多态反序列化
- 保证结构灵活
- 与前端自由 JSON 协议更匹配
🔹 JSONB 局部更新(非常关键)
例如更新消息的 mediaStatus:
UPDATE wx_message
SET payload = jsonb_set(payload, '{mediaStatus}', to_jsonb('uploaded'), true)
WHERE id = 123;
优点:
- 原子更新,不需要查出来再写回
- 不会发生并发覆盖
- 比读取->反序列化->再保存快得多
Spring JPA 版本:
@Modifying
@Transactional
@Query("""
UPDATE wx_message
SET payload = jsonb_set(payload, '{mediaStatus}', to_jsonb(:status), true)
WHERE session_id = :sessionId AND wxid = :messageId
""")
int updateMediaStatus(Long sessionId, String messageId, String status);
08|总结:选型建议
✔ 默认选 JSONB
- 查询快
- 索引强
- 占用小
- 支持局部更新
- 满足绝大多数实际业务需求
❗仅在以下场景用 JSON:
- 必须保留原始格式(日志、协议原文)
- JSON 不参与任何查询
本文由mdnice多平台发布