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 字段