jsonb [] vs jsonb,其中json是一个数组

时间:2019-06-17 04:00:40

标签: json postgresql

我有一个Postgres表mytable,其中一个字段如下:

myField JSONB[] NOT NULL

,让我们假设上述json的格式如下:

{ "letter":"A", "digit":30}

我应该使用哪些查询

  • 提取digit值的数组?
  • 提取包含digit值的json数组?
  • 提取digit值的数组,其中digit > 20
  • 提取一个digit值的json数组,其中digit > 20

如果将数据存储为json(其中json是列表),上述查询将如何更改?

  • 我仍然可以进行上述所有查询吗?
  • 性能会有什么不同?
  • 何时应选择一个?

1 个答案:

答案 0 :(得分:2)

让我们创建一个表,该表具有一个名为jsonb[]的类型pg_array的列(将存储一个数组JSON对象)和一个名为jsonb的类型json_array的列,该列将存储一个JSON对象。存储对象的JSON数组:

CREATE TABLE mytable (id int, pg_array jsonb[], json_array jsonb);
INSERT INTO mytable VALUES
    (1, ARRAY['{"letter":"A", "digit":30}', '{"letter":"B", "digit":31}']::jsonb[], '[{"letter":"A", "digit":30},{"letter":"B", "digit":31}]'),
    (2, ARRAY['{"letter":"X", "digit":40}', '{"letter":"Y", "digit":41}']::jsonb[], '[{"letter":"X", "digit":40},{"letter":"Y", "digit":41}]');

这两种方法的查询看起来非常相似,因为我们将处理单个数组元素,这意味着我们必须取消嵌套并再次聚集。

取消嵌套pg_array并获取每个jsonb对象:

SELECT unnest(pg_array);

取消嵌套json_array并获取每个jsonb对象:

SELECT jsonb_array_elements(json_array);

那是唯一的区别。因此,下面的查询看起来几乎相同。

关于您的第一组问题:

  

提取数字值的数组?

db=# SELECT array_agg((x->>'digit')::int) FROM mytable, unnest(pg_array) x GROUP BY id;
 array_agg
-----------
 {40,41}
 {30,31}
(2 rows)
db=# SELECT array_agg((x->>'digit')::int) FROM mytable, jsonb_array_elements(json_array) x GROUP BY id;
 array_agg
-----------
 {40,41}
 {30,31}
(2 rows)
  

提取包含数字值的json数组?

db=# SELECT jsonb_agg((x->>'digit')::int) FROM mytable, unnest(pg_array) x GROUP BY id;
 jsonb_agg
-----------
 [40, 41]
 [30, 31]
(2 rows)
db=# SELECT jsonb_agg((x->>'digit')::int) FROM mytable, jsonb_array_elements(json_array) x GROUP BY id;
 jsonb_agg
-----------
 [40, 41]
 [30, 31]
(2 rows)
  

提取数字值的数组,其中digit> 20?

(我在这里用的是30而不是20。)

db=# SELECT array_agg((x->>'digit')::int) FROM mytable, unnest(pg_array) x WHERE (x->>'digit')::int > 30 GROUP BY id;
 array_agg
-----------
 {40,41}
 {31}
(2 rows)
db=# SELECT array_agg((x->>'digit')::int) FROM mytable, jsonb_array_elements(json_array) x WHERE (x->>'digit')::int > 30 GROUP BY id;
 array_agg
-----------
 {40,41}
 {31}
(2 rows)
  

提取数字值的json数组,其中digit> 20?

(我在这里用的是30而不是20。)

db=# SELECT jsonb_agg((x->>'digit')::int) FROM mytable, unnest(pg_array) x WHERE (x->>'digit')::int > 30 GROUP BY id;
 jsonb_agg
-----------
 [40, 41]
 [31]
(2 rows)
db=# SELECT jsonb_agg((x->>'digit')::int) FROM mytable, jsonb_array_elements(json_array) x WHERE (x->>'digit')::int > 30 GROUP BY id;
 jsonb_agg
-----------
 [40, 41]
 [31]
(2 rows)

关于第二组问题:

  

我仍然可以进行上述所有查询吗?

如上所述,是的。

  

性能会有什么不同?

这归结为unnestjsonb_array_elements的性能差异。让我们将其与包含具有1,000,000个JSON对象的数组的单行进行比较:

TRUNCATE mytable;
INSERT INTO mytable
SELECT 1, array_agg(o), jsonb_agg(o)
FROM (SELECT jsonb_build_object('letter', 'A', 'digit', i) o FROM generate_series(1, 1000000) i) x;
phil=# EXPLAIN ANALYZE SELECT unnest(pg_array) FROM mytable;
                                                QUERY PLAN
-----------------------------------------------------------------------------------------------------------
 ProjectSet  (cost=0.00..35.88 rows=5000 width=32) (actual time=33.357..120.393 rows=1000000 loops=1)
   ->  Seq Scan on mytable  (cost=0.00..10.50 rows=50 width=626) (actual time=0.010..0.013 rows=1 loops=1)
 Planning time: 0.050 ms
 Execution time: 175.670 ms
(4 rows)

phil=# EXPLAIN ANALYZE SELECT jsonb_array_elements(json_array) FROM mytable;
                                                QUERY PLAN
-----------------------------------------------------------------------------------------------------------
 ProjectSet  (cost=0.00..35.88 rows=5000 width=32) (actual time=257.313..399.883 rows=1000000 loops=1)
   ->  Seq Scan on mytable  (cost=0.00..10.50 rows=50 width=721) (actual time=0.010..0.014 rows=1 loops=1)
 Planning time: 0.047 ms
 Execution time: 455.275 ms
(4 rows)

由此看来,unnestjsonb_array_elements快2.5倍。

  

何时应选择一个?

我认为您的数据集不足以发挥unnestjsonb_array_elements之间的性能差异。因此,我只选择在数据方面更有意义的内容。我倾向于使用jsonb[],因为它更清楚地表明您将拥有一个json对象数组。