全书目录

第八篇:PostgreSQL 完全指南 —— 时间档案馆宇宙

第十一章:JSONB —— 让档案里允许有“附页”,但别把整本表都写成附页

1 分钟 412 字 第 175 / 962 个阅读单元

PostgreSQL 同时支持 jsonjsonb

最实用的结论是:

业务里大多数场景优先用 jsonb

原因很简单:

  • json 保留原始文本形式
  • jsonb 会转成更适合处理的二进制结构
  • jsonb 支持索引,查询通常更高效

比如给通行证附上半结构化信息:

sql
UPDATE permits
SET meta = jsonb_build_object(
  'channel', 'mobile',
  'reviewer', 'robot-3',
  'tags', jsonb_build_array('fast-lane', 'night')
)
WHERE permit_id = 42;

查 JSONB 内容:

sql
SELECT permit_id, meta
FROM permits
WHERE meta @> '{"channel":"mobile"}';

取字段:

sql
SELECT
  permit_id,
  meta ->> 'reviewer' AS reviewer
FROM permits;

给 JSONB 建 GIN 索引:

sql
CREATE INDEX idx_permits_meta_gin
ON permits USING GIN (meta);

如果你的查询大多是 containment / jsonpath 匹配,还可以考虑:

sql
CREATE INDEX idx_permits_meta_path_gin
ON permits USING GIN (meta jsonb_path_ops);

要点是:

  • jsonb_ops 更通用
  • jsonb_path_ops 更小、更快,但支持的操作符更窄

如果你经常只查某个 JSON 路径,表达式索引更划算:

sql
CREATE INDEX idx_permits_meta_tags
ON permits USING GIN ((meta -> 'tags'));

但要记住一句非常重要的话:

JSONB 是给“边缘字段、变化字段、外部载荷”用的,不是让你把整个业务模型全塞进一个大 JSON。

下面这种设计通常是坏味道:

text
permits(
  id bigint,
  data jsonb   -- 把所有字段都塞进去
)

因为这样你会失去:

  • 清晰约束
  • 外键关系
  • 精准类型
  • 更稳定的优化空间

正确姿势通常是:

text
稳定主干字段 -> 正规列
变化较大的附加信息 -> JSONB