14 UUID 与 JSONB
PostgreSQL 中两种最受欢迎的非基础类型:uuid 用于不透明、全局唯一的标识符,jsonb 用于可建立索引并查询的二进制编码 JSON。UUID 是顺序整数 ID 的标准替代方案,适用于需要 ID 不可猜测、可在客户端生成或跨系统全局唯一的场景。对于半结构化数据,jsonb 让 PostgreSQL 足以与文档存储系统竞争。
本章要点
- 使用
gen_random_uuid()生成 UUID - 使用
jsonb存储并查询 JSON ->、->>、#>、#>>操作符及其返回值@>包含关系操作符(以及它如何使用 GIN 索引)json与jsonb的区别
示例
gen_random_uuid() 会生成随机的版本 4 UUID。从 PostgreSQL 13 开始它就是内置函数,不需要 pgcrypto 扩展。PostgreSQL 17 没有内置的 UUIDv7 生成器;如果需要按时间排序的 UUID,请使用应用程序/库或扩展。PostgreSQL 18 新增 uuidv7()。bigint 标识列也是一种选择。
对于 JSON,优先使用 jsonb 而不是 json。json 会原样存储输入文本(包括空白和键顺序);jsonb 会解析、规范化并以二进制形式存储。通常对 jsonb 建立索引并进行高效查询,几乎所有应用都使用它。只有在需要逐字节保留输入(这种情况很少见)时,才使用普通 json。
-> 操作符提取并返回 jsonb。->> 提取并返回 text(去掉 JSON 引号)。#> 和 #>> 使用路径(由键/下标组成的数组)。@>(“包含”)测试左值是否包含右值——它是 JSON 查询的基础。
运行示例
运行方式:
常见陷阱
- 将
data -> 'name'与字符串比较:data -> 'name' = '"Alice"'可以工作(注意带 JSON 引号的字符串),但通常应该使用data ->> 'name' = 'Alice'。 - 忘记建立索引:对没有 GIN 索引的
jsonb列进行过滤会执行全表扫描。CREATE INDEX ON docs_example USING gin (data);让@>及类似查询能够使用索引。 - 就地修改 jsonb:
UPDATE t SET data = data || '{"k": "v"}'::jsonb会添加或替换顶层键;jsonb_set可以修改嵌套路径。 jsonb内部的模式漂移:它很灵活,但你仍需知道其中有什么。记录预期结构,并在应用层或使用 CHECK 约束进行验证。
只为你查询的 JSON 部分建立索引。与其给整个 data 列建立 GIN 索引,不如给单一路径建立索引:CREATE INDEX ON docs_example ((data ->> 'name'));。这是一个 B-树表达式索引——小巧、快速且精确。
使用 ->> 以文本形式获取名称:SELECT '{"name": "Alice"}'::jsonb ->> 'name';。插入一条带有嵌套数据的记录,并使用 #>> 查询嵌套字段。然后在 data 上建立 GIN 索引,并使用 @> 进行包含查询。
下载
SQL 文件:uuid-jsonb.sql · 全部示例文件 · 准备工作