0

We have the following json documents stored in our PG table (identities) in a jsonb column 'data':

{
    "email": {
        "main": "[email protected]",
        "prefix": "aliasPrefix",
        "prettyEmails": ["stuff1", "stuff2"]
    },
    ...
}

I have the following index set up on the table:

CREATE INDEX ix_identities_email_main
  ON identities
  USING gin
  ((data -> 'email->main'::text) jsonb_path_ops);

What am I missing that is preventing the following query from hitting that index?? It does a full seq scan on the table... We have tens of millions of rows, so this query is hanging for 15+ minutes...

SELECT * FROM identities WHERE data->'email'->>'main'='[email protected]';
4
  • I've also tried data @> '{"email": {"main": "[email protected]"}}' But that not only misses the index as well, it isn't really the query I want anyways because of the other properties on the email object. Commented Dec 18, 2015 at 18:09
  • Can you share the query plan generated (EXPLAIN ...)? Commented Dec 18, 2015 at 18:23
  • Sure thing: " Filter: (((data -> 'email'::text) ->> 'main'::text) = '[email protected]'::text)" Commented Dec 18, 2015 at 19:31
  • 1
    wiki.postgresql.org/wiki/Slow_Query_Questions Commented Dec 18, 2015 at 23:02

1 Answer 1

2

If you use JSONB data type for your data column, in order to index ALL "email" entry values you need to create following index:

CREATE INDEX ident_data_email_gin_idx ON identities USING gin ((data -> 'email'));

Also keep in mind that for JSONB you need to use appropriate list of operators;

The default GIN operator class for jsonb supports queries with the @>, ?, ?& and ?| operators

Following queries will hit this index:

SELECT * FROM identities
WHERE data->'email' @> '{"main": "[email protected]"}'
-- OR
SELECT * FROM identities
WHERE data->'email' @> '{"prefix": "aliasPrefix"}'

If you need to search against array elements "stuff1" or "stuff2", index above will not work , you need to explicitly add expression index on "prettyEmails" array element values in order to make query work faster.

CREATE INDEX ident_data_prettyemails_gin_idx ON identities USING gin ((data -> 'email' -> 'prettyEmails'));

This query will hit the index:

SELECT * FROM identities
WHERE data->'email' @> '{"prettyEmails":["stuff1"]}'
Sign up to request clarification or add additional context in comments.

Comments

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.