PostgreSQL引入的JSONB解释

495

PostgreSQL 刚在 9.4 版本中引入了 JSONB,而且已经成为 Hacker News 上的热门话题。它与之前在 PostgreSQL 中存在的 Hstore 和 JSON 有何不同?

JSONB 有哪些优势和限制?什么时候应该考虑使用它?


6
从PGCon2014: https://www.youtube.com/watch?v=oQ1LSW31Y1A&list=PLWW0CjV-Tafa2jvcjihXwSvZZKsLAsb9Y#t=2492这是一个指向PGCon2014演讲的链接,具体时间为2492秒处。由于没有提供需要翻译的具体内容,请提供需要翻译的内容以便我可以提供更准确的翻译。 - msanford
6
@CraigRinger提供的链接不够精确,现在已经过去一年了,它甚至不能准确定位到与JSONB相关的内容。 - berkus
2
@berkus 我本以为我已经链接到了具体的帖子。真是令人沮丧。 - Craig Ringer
1
它确实指向特定的视频。 - talonx
9个回答

626

首先,hstore 是一个贡献模块,仅允许您存储键=>值对,其中键和值只能是 text 类型(但值也可以是 sql 的 NULL)。

jsonjsonb 都允许您存储有效的 JSON (在其规范中定义)。

例如,以下是有效的 JSON 表示形式:null, true, [1,false,"string",{"foo":"bar"}], {"foo":"bar","baz":[null]} - 与 JSON 相比,hstore 只是一个小子集(但如果您只需要此子集,则没问题)。

jsonjsonb 之间唯一的区别是它们的存储方式:

  • json 存储在其纯文本格式中,而
  • jsonb 存储在某些二进制表示中

这有三个主要的后果:

  • jsonb 通常需要比 json 更多的磁盘空间来存储(有时候不需要)
  • jsonb 从其输入表示构建所需的时间比 json 更长
  • json 操作所需的时间比 jsonb 还要明显地更长(并且每次在 json 类型值上执行某些操作时都需要进行解析)

jsonb 在稳定版本中可用时,将有两个主要用例可以轻松选择它们之间的区别:

  1. 如果您的应用程序仅使用JSON表示,并且PostgreSQL仅用于存储和检索此表示,则应使用json
  2. 如果您在PostgreSQL中对JSON值执行大量操作,或者使用某些JSON字段上的索引,则应使用jsonb

1
你好,既然它具有二进制表示,为什么 jsonb 不支持这个呢?从 CREATE TABLE test(id SERIAL PRIMARY KEY, data JSONB);UPDATE test SET data->'a' = 123 WHERE id = 1; - Kokizzu
4
补充一点,你可能会选择使用 json 而不是 jsonb 的原因之一是,如果由于遗留问题,消费你的 json 数据的代码依赖于 json 字段的顺序,而这些字段无法重新排序。 - djdrzzy
4
关于遗留问题:在 JSON 中,如果一个对象(表、映射、哈希,无论在主机语言中如何称呼)的键值对按不同顺序排列,就没有语义上的区别。如果您依赖这个顺序,实际上您正在使用与 JSON 不同的东西。-- 对于“text”和“json”:后者具有 JSON 验证,因此在出现无效 JSON 时,它只会在插入时失败,而不是每次应用程序读取时都失败(因为它得到了无效表示)。另外,您可以在数据库中安全地将后者转换为 jsonb - pozs
2
这是一篇很棒的文章,解释了JSONB的实现细节(http://pgeoghegan.blogspot.com/2014/03/what-i-think-of-jsonb.html)。 - manugupt1
显示剩余2条评论

188

Peeyush:

简短回答:

  • 如果您在 PostgreSQL 中进行大量 JSON 操作,例如排序、切片、拼接等,则应出于速度原因使用 JSONB。
  • 如果需要对 JSON 进行任意键值搜索的索引查找,则应使用 JSONB。
  • 如果以上两者都不是您要做的事情,则应该使用 JSON。
  • 如果需要保留键顺序、空格和重复键,则应使用 JSON。

更详细的回答,请等待我在接近 9.4 发布时进行完整的“如何”撰写。


128

JSON和JSONB之间的区别简单解释(原始图像由PostgresProfessional提供):

SELECT '{"c":0,   "a":2,"a":1}'::json, '{"c":0,   "a":2,"a":1}'::jsonb;

          json          |        jsonb 
------------------------+--------------------- 
 {"c":0,   "a":2,"a":1} | {"a": 1, "c": 0} 
(1 row)
  • json:文本存储“按原样”
  • jsonb:无空格
  • jsonb:没有重复的键,最后一个键获胜
  • jsonb:键已排序

更多信息请参见演讲视频幻灯片展示,由jsonb开发人员介绍。此外,他们还推出了JsQuery,一种提供强大的jsonb查询语言的pg扩展。


1
谢谢,我已经将其替换为文本。 - ChelowekKot

67
  • hstore 是一种“宽列”存储类型,它是一个扁平(非嵌套)的键值对字典,始终以合理高效的二进制格式存储(哈希表,因此得名)。
  • json 将JSON文档存储为文本,并在存储文档时执行验证,在需要时解析它们(即访问单个字段)。它应支持整个JSON规范。由于整个JSON文本被存储,所以其格式被保留。
  • jsonb 为了性能而采取了捷径:输入时解析JSON数据并以二进制格式存储,字典中的键排序不会维护,重复的键也不会维护。访问JSONB字段中的单个元素很快,因为它不需要一直解析JSON文本。输出时,JSON数据被重构,初始格式丢失。

在处理机器可读数据时,jsonb 可用时没有明显的原因使用它。


61

JSONB是JSON的“更好”的版本。

让我们看一个例子:

SELECT '{"c":0,   "a":2,"a":1}'::json, '{"c":0,   "a":2,"a":1}'::jsonb;
          json          |        jsonb 
------------------------+--------------------- 
 {"c":0,   "a":2,"a":1} | {"a": 1, "c": 0} 
(1 row)
  1. JSON 存储了空格,因此当键"a"被存储时,我们可以看到空格,而 JSONB 则不会。
  2. JSON 存储了一个键的所有值。这就是为什么你可以看到键"a"对应多个值(2和1),而 JSONB 只“存储”最后一个值。
  3. JSON 保持插入元素的顺序,而 JSONB 保持“排序”的顺序。
  4. JSONB 对象以解压缩的二进制形式存储,而不是 JSON 中的“原始数据”,在检索时无需重新解析数据。
  5. JSONB 还支持索引,这可能是一个显著的优势。

一般来说,除非有关于对象键排序的传统假设等特殊需求,否则应该优先选择 JSONB。


34
关于jsonjsonb数据类型之间的区别,值得一提的是官方解释:
PostgreSQL提供两种用于存储JSON数据的类型:jsonjsonb。为了实现这些数据类型的高效查询机制,PostgreSQL还提供了在第8.14.6节中描述的jsonpath数据类型。 jsonjsonb数据类型接受几乎相同的输入值集合。主要的实际差异在于效率。json数据类型存储输入文本的精确副本,处理函数必须在每次执行时重新解析;而jsonb数据以分解的二进制格式存储,由于没有重新解析,因此输入略慢,但处理速度显着快。jsonb还支持索引,这可能是一个重要的优势。
由于json类型存储输入文本的精确副本,因此它将保留标记之间的语义上不重要的空格以及JSON对象内键的顺序。此外,如果值内的JSON对象包含多个相同的键,则保留所有键/值对。(处理函数将最后一个值视为有效值。)相反,jsonb不保留空格,不保留对象键的顺序,并且不保留重复的对象键。如果输入中指定了重复键,则仅保留最后一个值。
一般来说,大多数应用程序应该首选将JSON数据存储为jsonb,除非有相当专业的需要,例如关于对象键排序的遗留假设。
PostgreSQL每个数据库只允许一种字符集编码。因此,除非数据库编码为UTF8,否则JSON类型无法严格符合JSON规范。直接包含无法表示为数据库编码的字符将失败;反之,允许使用数据库编码但不能在UTF8中表示的字符。
来源: https://www.postgresql.org/docs/current/datatype-json.html

20

我今天参加了PostgresOpen,基准测试比MongoDB快多了。对于selects查询,速度大约快了500%,几乎所有操作都比MongoDB快,至少快了200%。目前唯一的例外是更新操作需要完全重写整个JSON列 - 这是MongoDB处理得更好。

JSONB上的gin索引听起来很棒。

此外,PostgreSQL将在内部持久化JSONB类型,并基本上与数字、文本、布尔等类型匹配。

使用JSONB也可以进行联接操作。

添加PLv8作为存储过程,这对于Node.js开发人员来说基本上是梦想成真。

由于JSONB存储为二进制,它还会剥离所有空格,更改属性顺序并删除重复属性(使用属性的最后一次出现)。

除了在针对JSON列进行查询时的索引外,PostgreSQL无需在每行上运行将文本转换为JSON的功能,这可能单独节省大量时间。


10

还有一个重要的区别,之前没有任何答案提到过,就是 json 类型没有等于运算符,但 jsonb 有。

这意味着当从表中选择此 json 类型和/或其他字段时,您不能使用DISTINCT 关键字(您可以使用 DISTINCT ON ,但由于像此类情况而不总是可能)。


8
据我所知,
  • 目前(在PostgreSQL 9.3中)的hstore不允许将其他对象和数组嵌套作为其键/值对的值。然而,未来的hstore补丁将允许嵌套。该补丁不会在9.4版本中发布,并且可能不会很快被包含。

  • json允许嵌套,但它是基于文本的,并且不允许索引,因此速度较慢。

  • 即将在9.4中发布的jsonb将具有json的当前嵌套功能,以及hstore的GIN/GIST索引,因此速度较快。

正在开发PostgreSQL 9.4的人似乎在说,新的、快速的jsonb类型将吸引那些本来会选择使用NoSQL数据存储(如MongoDB)的人,但现在可以将关系型数据库和可查询的非结构化数据合并到一个平台上。

为什么HStore2/jsonb是9.4最重要的补丁

对于PostgreSQL 9.4 jsonb的基准测试似乎与MongoDB相当,甚至在某些情况下更快。

http://texture.io/alphabetum/postgresql-incl-hstore-vs-mongodb


最后一个链接已经失效:“DisallowedHost at /alphabetum/postgresql-incl-hstore-vs-mongodb” - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接