PostgreSQL 中 JSON 和 JSONB 数据类型的核心区别是什么
在 PostgreSQL 中,JSON 和 JSONB 数据类型的核心区别在于它们的存储格式以及由此带来的性能和功能差异。
简单来说:
- JSON 是以纯文本形式存储的(原样保存)。
- JSONB 是以二进制(Binary)格式存储的(解析后保存)。
以下是它们在具体机制上的核心区别和详细对比:
1. 核心区别详情
① 存储与解析方式 (Storage & Parsing)
- JSON:写入快,读取慢。 它是把输入的数据当作普通的文本字符串原封不动地存下来。因此,每次你在查询中操作或提取 JSON 数据时,数据库都需要在运行时重新解析这串文本。
- JSONB:写入稍慢,读取极快。 它在数据写入时,会先将 JSON 文本解析并转换为自定义的二进制格式存储。虽然写入时多了一步解析操作,但在查询时不需要再次解析,直接读取二进制数据。
② 数据细节的保留 (Formatting & Duplicates)
- JSON:完全保留原貌。 它会保留输入时的所有空格、缩进、换行。如果你的 JSON 中有重复的键(例如
{"a": 1, "a": 2}),它也会原样保留,并且保留键的原始输入顺序。 - JSONB:只保留核心数据。 它在解析时会去除所有多余的空格和缩进;重新排序键值对;如果存在重复的键,它只会保留最后一个(例如
{"a": 1, "a": 2}会被存为{"a": 2})。
③ 索引支持 (Indexing) —— 最关键的区别
- JSON:不支持直接在 JSON 结构上建立高级索引。你只能提取出其中的某个字符串,然后针对那个普通的文本字段建 B-Tree 索引。
- JSONB:拥有强大的索引支持。 它可以建立 GIN 索引(广义倒排索引),这使得你可以极其高效地搜索 JSON 文档内部的结构。例如,快速查找“包含某个键的记录”或“某个键的值等于 X 的记录”。支持
@>(包含)、?(存在键)等高级操作符。
2. 快速对比表
| 特性 | JSON 类型 |
JSONB 类型 |
|---|---|---|
| 存储格式 | 纯文本 (Text) | 二进制 (Decomposed Binary) |
| 写入速度 | 较快(直接存,不解析) | 稍慢(需要解析和转换) |
| 查询速度 | 慢(每次查询都需要实时解析) | 极快(无需解析,直接处理) |
| 空格与缩进 | 完全保留 | 被删除 |
| 键的顺序 | 完全保留 | 被重新排序(不可预测) |
| 重复的键 | 全部保留 | 只保留最后一个 |
| 高级索引 (GIN) | 不支持 | 完全支持 |
| 高级操作符 | 仅支持基础提取 (->, ->>) |
支持包含(@>)、存在(?)、删除(-)等 |
3. 直观的代码演示
当你插入带有空格和重复键的数据时:
sql
-- 插入 JSON
SELECT '{"a": 1, "b": 2, "a": 3}'::json;
-- 结果原样输出: {"a": 1, "b": 2, "a": 3}
-- 插入 JSONB
SELECT '{"a": 1, "b": 2, "a": 3}'::jsonb;
-- 结果被压缩且去重: {"a": 3, "b": 2}
4. 总结:应该用哪个?
99% 的情况下,请使用
JSONB。
只要你的应用需要对 JSON 数据进行查询、过滤、更新或分析,JSONB都是绝对的首选,因为它的查询性能和强大的 GIN 索引是JSON无法比拟的。什么时候使用
JSON?(极其罕见)- 你把 PostgreSQL 仅仅当作一个“日志收集器”,只写入,极少查询,且要求极致的写入速度。
- 你的业务逻辑有特殊癖好,必须 100% 还原用户输入的原始字符串(包含特殊的空格、缩进或必须保留重复的键)。
- 你的数据只是用来“原样拿出来丢给前端”,数据库完全不关心其内部结构。
右滑查看面试常问