Postgres 9.4+ jsonb:嵌套在数组中的索引字典

use*_*947 3 postgresql indexing jsonb

给定一个表

create table tmp (data jsonb not null);
Run Code Online (Sandbox Code Playgroud)

和数据

insert into tmp (data) values ('{"root": [{"name": "item1"}, {"name": "item2"}]}');
Run Code Online (Sandbox Code Playgroud)

我需要索引 jsonb 列“数据”以快速回答诸如

select * from tmp where data->'root' @> '[{"name": "item1"}]';
Run Code Online (Sandbox Code Playgroud)

在 Postgres 9.4+ 中可以吗?

use*_*947 6

经过一番调试后,我了解到为外部 json 元素(例如“root”)创建的索引也适用于层次结构中的所有嵌套元素。所以在我的例子中正确的解决方案是:

CREATE INDEX idx_tmp_data_root ON tmp USING gin ((data->'root') jsonb_path_ops);
Run Code Online (Sandbox Code Playgroud)

我选择jsonb_path_ops索引运算符类,因为它根据需要支持包含查询@>,并且与默认索引类型相比,它会产生更紧凑、更快的索引。

这是完整的演示:

首先,创建一个表并加载数据:

-> SET enable_seqscan = OFF; -- force postgres to use indices if any
-> create temporary table tmp (data jsonb not null);
-> insert into tmp (data) values ('{"root": [{"name": "item1"}, {"name": "item2"}]}');
Run Code Online (Sandbox Code Playgroud)

不带索引的查询:

-> explain select * from tmp where data->'root' @> '[{"name": "item1"}]';

QUERY PLAN
Seq Scan on tmp  (cost=10000000000.00..10000000029.65 rows=1 width=32)
   Filter: ((data -> 'root'::text) @> '[{"name": "item1"}]'::jsonb)
(2 rows)
Run Code Online (Sandbox Code Playgroud)

使用索引查询:

-> CREATE INDEX idx_tmp_data_root ON tmp USING gin ((data->'root') jsonb_path_ops);
-> explain select * from tmp where data->'root' @> '[{"name": "item1"}]';

QUERY PLAN
Bitmap Heap Scan on tmp  (cost=8.00..12.02 rows=1 width=32)
  Recheck Cond: ((data -> 'root'::text) @> '[{"name": "item1"}]'::jsonb)
  ->  Bitmap Index Scan on idx_tmp_data_root  (cost=0.00..8.00 rows=1 width=0)
    Index Cond: ((data -> 'root'::text) @> '[{"name": "item1"}]'::jsonb)
(4 rows)

-> SET enable_seqscan = ON;
Run Code Online (Sandbox Code Playgroud)