3

Given a table

create table tmp (data jsonb not null);

and data

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

I need to index jsonb column 'data' to quickly answer queries like

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

Is it possible in Postgres 9.4+?

2
  • 1
    CREATE INDEX ON tmp((data->>'root'));? Commented Sep 1, 2017 at 17:36
  • @Hackerman you were close: a correct solution appears to be data->'root'. Commented Sep 1, 2017 at 20:47

1 Answer 1

6

After a bit of debugging, I learned that indices created for outer json elements (e.g. "root") also apply to all the nested elements in the hierarchy. So the correct solution in my case is:

CREATE INDEX idx_tmp_data_root ON tmp USING gin ((data->'root') jsonb_path_ops);

I opted for jsonb_path_ops index operator class since it supports containment queries @> as required and results in a more compact and faster index as opposed to a default index type.

And here is a full demonstration:

First, create a table and load data:

-> 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"}]}');

Query without an index:

-> 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)

Query with an index:

-> 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;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for sharing this. Well done, helped me a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.