【问题标题】:Postgres: Are There Downsides to Using a JSON Column vs. an integer[] Column?Postgres:使用 JSON 列与 integer[] 列有缺点吗?
【发布时间】:2018-03-31 21:55:20
【问题描述】:

TLDR:如果我想在 Postgres 表中保存整数数组,使用数组列 (integer[]) 与使用 JSON 列(例如。一个比另一个表现更好)?

背景故事:

我正在使用 PostgreSQL 数据库,并使用 Node/Knex 来管理它。 Knex 没有任何方法可以直接定义 PostgreSQL integer[] 列类型,因此有人提交了一个 Knex 错误要求...但其中一位 Knex 开发人员关闭了票证,基本上说没有必要支持 PostgreSQL当任何人都可以使用 JSON 列类型时,数组列类型。

我的问题是,使用 JSON 列类型来保存一个简单的整数数组有什么缺点(如果有的话)?使用真正的数组列是否有任何好处(例如提高性能),或者仅将数组存储在 JSON 列中是否也同样好?

编辑:为了清楚起见,我在答案中寻找的只是以下之一:

A) 对 PostgreSQL 中 JSON 列和 integer[] 列如何工作的解释,包括一个比另一个更好或两者如何(至少大致)相等。

B) 没有解释,但至少参考了一些基准,表明一种或另一种列类型表现更好(或两者相等)

【问题讨论】:

  • JSON(B) 是比简单数组复杂得多的类型,因此需要更多操作(至少在内部)来管理其值;数组可以以简单的方式被索引,而 JSON 数组不能(据我所知);在 PostgreSQL 中有很多函数/运算符来处理数组,而对于 JSON(B) 数组,只有一种方法是将其转换为一组值并逐个处理它们......
  • 是的,我主要对 JSON 而非 JSON(B) 感到好奇。至于 integer[] 列被索引而 JSON 不被索引,这也是我最初的想法,但 Knex 的人往往对数据库非常了解,所以我认为他们使用 JSON 的建议可能是基于对问题(因为我远非 Postgres 专家)。
  • 简而言之:如果您需要一个整数数组,请使用整数数组。您始终可以使用to_json()to_jsonb() 函数将其转换为JSON 数组。 Docdoc.
  • JSON(B) 列可以被索引,但条件有限(例如,key=valuefield contains some keyDoc
  • 对不起,我可以发表一下PostgreSQL方面的意见。而且我不知道为什么 Knex 开发人员认为使用 JSON 列可能比自然类型更有效(除了解析包含 JSON 的字符串对他们来说更简单)

标签: postgresql knex.js


【解决方案1】:

int[] 在所需的存储方面效率更高。考虑以下查询,它返回包含 500 个元素的数组的大小

select pg_column_size(array_agg(i)) as array_size, 
       pg_column_size(jsonb_agg(i)) as jsonb_size,
       pg_column_size(json_agg(i)) as json_size
from  generate_series(1,500) i;

返回:

array_size | jsonb_size | json_size
-----------+------------+----------
      2024 |       6008 |      2396

(我很惊讶 JSON 的值比 JSONB 小得多,但这是另一个话题)


如果您总是将数组用作 single 值,则查询性能并不重要但是如果您确实需要查看数组并搜索特定值,使用本机数组将更有效。

native arrays 可用的函数和运算符比 JSON 数组要多得多。您可以轻松地在 JSON 数组中搜索单个值,但搜索多个值需要变通方法。

以下查询表明:

with array_test (id, int_array, json_array) as (
  values
    (1, array[1,2,3], '[1,2,3]'::jsonb)
)
select id, 
       int_array @> array[1] as array_single,
       json_array @> '1' json_single,
       int_array @> array[1,2] as array_all,
       json_array ?& array['1','2'] as json_all,
       int_array && array[1,2] as array_any,
       json_array ?| array['1','2'] as json_any
from array_test;

如果数组包含一个特定值,您可以轻松查询它。这也适用于 JSON 数组。这些是表达式array_singlejson_single。使用本机数组,您也可以改用 1 = any(int_array)

但是检查一个数组是否包含列表中的所有值,或者列表中的任何值都不适用于 JSON 数组。

以上测试查询返回:

id | array_single | json_single | array_all | json_all | array_any | json_any
---+--------------+-------------+-----------+----------+-----------+---------
 1 | true         | true        | true      | false    | true      | false   

【讨论】:

  • 完美:您的回答内容丰富,回答了问题,让我更好地理解了 Postgres。谢谢!
  • 实际上说there is not a single function or operator that supports searching inside a JSON array的部分是不正确的(我也将jsonb计入通用术语JSON)。 @>, ?, ?|等都支持从 jsonb 数组查询,还可以创建索引以使这些操作高效。 Creating Indexes 用于 jsonb 数组/列 is not nearly impossible,但实际上很容易(几年前我写了一篇关于它的博客文章 vincit.fi/en/blog/objection-js-postgresql-power-json-queries 最后是关于创建索引的信息)。
  • @MikaelLepist:嗯,我很确定@> 不适用于数组。感谢您的反馈。但是例如?|?& 检查多个值似乎不起作用:rextester.com/QEVK30483
  • 你说得对,我完全记错了 ? 运算符在 jsonb 中的用途。它们确实适用于查询 josnb 对象中是否存在键(对于 jsonb 数组始终为 false)。
猜你喜欢
  • 2019-09-15
  • 2018-11-03
  • 2019-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
  • 2020-07-07
相关资源
最近更新 更多