PostgreSQL 在 JSONB[] 上创建索引

PostgreSQL create index on JSONB[]

考虑一个 table 定义如下:

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 键上没有索引,select 查询使用 unnest 操作,如下所示:

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

问题是,如果 table 有大量的行,上面的查询将不仅包括完整的 table 扫描,而且还会过滤每个 jsonb数组。

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

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

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

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

不幸的是,to_jsonb() 未标记为 immutable(我猜是因为其中可能存在时间戳转换),如果您想在索引中使用表达式,这是必需的。

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

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}]'

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

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