PostgreSQL 在 JSONB[] 上创建索引

Posted

技术标签:

【中文标题】PostgreSQL 在 JSONB[] 上创建索引【英文标题】:PostgreSQL create index on JSONB[] 【发布时间】:2021-02-10 17:02:14 【问题描述】:

考虑如下定义的表:

CREATE TABLE test (
    id int4 NOT NULL,
    tag_counts _jsonb NOT NULL DEFAULT ARRAY[]::jsonb[]
);

INSERT INTO test(id, tag_counts) values(1,array['"type":1, "count":4','"type":2, "count":10' ]::jsonb[])

如何在 json 键 type 上创建索引以及如何对其进行查询?

编辑:以前,json键上没有索引,选择查询使用unnest操作,如下所示:

select * from (SELECT unnest(tag_counts) as tc
FROM public.test) as t
where tc->'type' = '2';

问题是,如果表的行数很大,上面的查询不仅会包括全表扫描,还会对每个jsonb数组进行过滤。

【问题讨论】:

jsonb[] 几乎没有意义。为什么不在jsonb 列中存储正确的 JSON 数组?例如'["type":1, "count":4','"type":2, "count":10]' 遗留问题。如果不进行重大重构,就无法真正改变它。 那么它是如何在遗留系统中被索引的呢?您想加快什么查询? 更新了问题以包括它目前是如何完成的 【参考方案1】:

有一种方法可以对此进行索引,但不确定它的速度。

如果这是一个“常规”jsonb 列,您可以使用类似where tag_counts @> '["type": 2]' 的条件,它可以在该列上使用 GIN 索引。

如果将数组转换为“普通”json 值,则可以使用该运算符:

select *
from test
where to_jsonb(tag_counts) @> '["type": 2]'

不幸的是,to_jsonb() 没有被标记为不可变(我猜是因为那里潜在的时间戳转换),如果您想在索引中使用表达式,这是一个要求。

但是对于你的数据,这确实是不可变的,所以我们可以创建一个小包装函数:

create function as_jsonb(p_input jsonb[])
returns  jsonb
as
$$
  select to_jsonb(p_input);
$$
language sql
immutable;

通过这个函数,我们可以创建一个索引:

create index on test using gin ( as_jsonb(tag_counts) jsonb_path_ops);

您需要在查询中使用该函数:

select *
from test
where as_jsonb(tag_counts) @> '["type": 2]'

在一百万行的表上,我得到以下执行计划:

Bitmap Heap Scan on stuff.test  (cost=1102.62..67028.01 rows=118531 width=252) (actual time=15.145..684.062 rows=147293 loops=1)
  Output: id, tag_counts
  Recheck Cond: (as_jsonb(test.tag_counts) @> '["type": 2]'::jsonb)
  Heap Blocks: exact=25455
  Buffers: shared hit=25486
  ->  Bitmap Index Scan on ix_test  (cost=0.00..1072.99 rows=118531 width=0) (actual time=12.347..12.356 rows=147293 loops=1)
        Index Cond: (as_jsonb(test.tag_counts) @> '["type": 2]'::jsonb)
        Buffers: shared hit=31
Planning:
  Buffers: shared hit=23
Planning Time: 0.444 ms
Execution Time: 690.160 ms

【讨论】:

纯粹的天才。它显着改善了我的查询时间。感谢您的帮助。

以上是关于PostgreSQL 在 JSONB[] 上创建索引的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSql jsonb 列上的 GIN 索引未在查询中使用

使用 Sequelize.js 和 PostgreSQL 在关联模型上查询 JSONB 字段

在 postgresql 中,如何在 jsonb 键上返回布尔值而不是字符串?

PostgreSQL - jsonb_each

PostgreSql jsonb 字段查看

用于比较 JSONB 值的 PostgreSQL 索引