Re: Is it possible to index "deep" into a JSONB column?

From: Imre Samu <pella(dot)samu(at)gmail(dot)com>
To: Shaheed Haque <shaheedhaque(at)gmail(dot)com>
Cc: "pgsql-generallists(dot)postgresql(dot)org" <pgsql-general(at)lists(dot)postgresql(dot)org>
Subject: Re: Is it possible to index "deep" into a JSONB column?
Date: 2022-05-30 10:50:14
Message-ID: CAJnEWwnL2mMwkhsJzBw=3aEvGHPiQ3TjmvnLZqbgEbPXrjS8Ng@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

> In principle, I believe this allows index-assisted access to keys and
> values nested in arrays and inner objects but in practice, it seems
> the planner "often" decides to ignore the index in favour of a table
scan.

part II. index usage ; see the "*Bitmap Index Scan on jpqarr_idx*"

SET enable_seqscan = OFF;
select * from jsonb_table
where jsonb_path_query_array( jsonb_col, '$.employee.*.date_of_birth') @>
to_jsonb('1971-02-02'::TEXT);
;
+----+---------------------------------------------------------------------------------------------------------------+
| id | jsonb_col
|
+----+---------------------------------------------------------------------------------------------------------------+
| 2 | {"stuff": {}, "employee": {"7011": {"date_of_birth": "1970-01-01"},
"7122": {"date_of_birth": "1971-02-02"}}} |
+----+---------------------------------------------------------------------------------------------------------------+
(1 row)

EXPLAIN ANALYZE select * from jsonb_table
where jsonb_path_query_array( jsonb_col, '$.employee.*.date_of_birth') @>
to_jsonb('1971-02-02'::TEXT);
;
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
|
QUERY PLAN
|
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| Bitmap Heap Scan on jsonb_table (cost=3.00..4.52 rows=1 width=36)
(actual time=0.056..0.059 rows=1 loops=1)
|
| Recheck Cond: (jsonb_path_query_array(jsonb_col,
'$."employee".*."date_of_birth"'::jsonpath, '{}'::jsonb, false) @>
to_jsonb('1971-02-02'::text)) |
| Heap Blocks: exact=1

|
| -> *Bitmap Index Scan on jpqarr_idx * (cost=0.00..3.00 rows=1 width=0)
(actual time=0.026..0.027 rows=1 loops=1)
|
| *Index Cond: (jsonb_path_query_array(jsonb_col,
'$."employee".*."date_of_birth"'::jsonpath, '{}'::jsonb, false) @>
to_jsonb('1971-02-02'::text))* |
| Planning Time: 0.255 ms

|
| Execution Time: 0.122 ms

|
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
(7 rows)

regards,
Imre

Imre Samu <pella(dot)samu(at)gmail(dot)com> ezt írta (időpont: 2022. máj. 30., H,
12:30):

> Hi Shaheed,
>
> > WHAT GOES HERE
>
> imho check the: *jsonb_path_query_array( jsonb_col,
> '$.employee.*.date_of_birth' ) *
>
> may example:
>
> CREATE TABLE jsonb_table (
> id serial primary key,
> jsonb_col JSONB
> );
>
> INSERT INTO jsonb_table(jsonb_col)
> VALUES
> ('{"stuff": {},"employee": {"8011": {"date_of_birth":
> "1980-01-01"},"8222": {"date_of_birth": "1982-02-02"}}}'),
> ('{"stuff": {},"employee": {"7011": {"date_of_birth":
> "1970-01-01"},"7122": {"date_of_birth": "1971-02-02"}}}'),
> ('{"stuff": {},"employee": {"a12": {"date_of_birth":
> "2000-01-01"},"b56": {"date_of_birth": "2000-02-02"}}}')
> ;
>
> select jsonb_path_query_array( jsonb_col, '$.employee.*.date_of_birth' )
> from jsonb_table;
>
> -- create index
> create index jpqarr_idx
> on jsonb_table
> using gin ( jsonb_path_query_array( jsonb_col,
> '$.employee.*.date_of_birth' ) );
> -- tests:
> select id from jsonb_table
> where jsonb_path_query_array( jsonb_col, '$.employee.*.date_of_birth')
> @> to_jsonb('2000-01-01'::TEXT);
> ;
> DROP TABLE
> CREATE TABLE
> INSERT 0 3
> +------------------------------+
> | jsonb_path_query_array |
> +------------------------------+
> | ["1980-01-01", "1982-02-02"] |
> | ["1970-01-01", "1971-02-02"] |
> | ["2000-01-01", "2000-02-02"] |
> +------------------------------+
> (3 rows)
>
> CREATE INDEX
> +----+
> | id |
> +----+
> | 3 |
> +----+
> (1 row)
>
>
> Regards,
> Imre
>
> Shaheed Haque <shaheedhaque(at)gmail(dot)com> ezt írta (időpont: 2022. máj. 29.,
> V, 22:53):
>
>> Suppose I have a JSONB field called "snapshot". I can create a GIN
>> index on it like this:
>>
>> create index idx1 on mytable using gin (snapshot);
>>
>> In principle, I believe this allows index-assisted access to keys and
>> values nested in arrays and inner objects but in practice, it seems
>> the planner "often" decides to ignore the index in favour of a table
>> scan. (As discussed elsewhere, this is influenced by the number of
>> rows, and possibly other criteria too).
>>
>> Now, I know it is possible to index inner objects, so that is snapshot
>> looks like this:
>>
>> {
>> "stuff": {},
>> "more other stuff": {},
>> "employee": {
>> "1234": {"date_of_birth": "1970-01-01"},
>> "56B789": {"date_of_birth": "1971-02-02"},
>> }
>> }
>>
>> I can say:
>>
>> create index idx2 on mytable using gin ((snapshot -> 'employee'));
>>
>> But what is the syntax to index only on date_of_birth? I assume a
>> btree would work since it is a primitive value, but WHAT GOES HERE in
>> this:
>>
>> create index idx3 on mytable using btree ((snapshot ->'employee' ->
>> WHAT GOES HERE -> 'date_of_birth'));
>>
>> I believe an asterisk "*" would work if 'employee' was an array, but
>> here it is nested object with keys. If it helps, the keys are
>> invariably numbers (in quoted string form, as per JSON).
>>
>> Thanks, Shaheed
>>
>>
>>

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message andrew cooke 2022-05-30 14:13:23 Appending data locally to a logical replication subscriber
Previous Message Imre Samu 2022-05-30 10:30:55 Re: Is it possible to index "deep" into a JSONB column?