0

I am using Postgres v 9.5.

I have a table with a column of type JSON. Trying to search data in that JSON column by using the following query:

select * from mytable where  data->'application_form_attributes'->>'5705' = 'ABCD';

To speedup the query I have tried to create an index :

CREATE INDEX myindex1 ON mytable USING btree (base_service_id,(data :: jsonb->'application_form_attributes'));

But I am getting the error:-

ERROR:  index row size 2744 exceeds maximum 2712 for index "myindex1"
HINT:  Values larger than 1/3 of a buffer page cannot be indexed.
Consider a function index of an MD5 hash of the value, or use full text indexing.
SQL state: 54000

mytable structure is:

  department_id integer,
  org_name character varying(250),
  base_service_id integer,
  service_id integer,
  service_name character varying(250),
  application_id integer NOT NULL,
  appl_ref_no character varying(50),
  submission_date timestamp without time zone,
  submission_mode_id integer,
  submission_mode character varying(150),
  submission_location character varying(250),
  data json,
  execution_data json,
  pending_task_json json,
  max_current_process_id integer,
  appl_status character(1),
  due_date timestamp without time zone,
  payment_mode_name character varying(200),
  version_no integer,
  appl_amount numeric(18,2),
  coverage_location_id integer,
  location_id integer,
  location_type_id integer,
  payment_mode_id integer,
  applied_by character varying,
  kiosk_registration_no character varying(50),
  last_task_at character varying(100),
  current_task_pending character varying(500),

  CONSTRAINT pk_table1_json PRIMARY KEY (application_id)

Need solution so that the search could be made fast.

Update :

My index that created successfully:

CREATE INDEX concurrently appl_processingjson_data_idx2 ON application_processing_json (CAST(md5(initiated_data :: text) AS uuid));

EXPLAIN output:

select * from application_processing_json where base_service_id = 721 and initiated_data->'application_form_attributes'->>'5734' = '9898989822';

"Seq Scan on application_processing_json (cost=0.00..109162.32 rows=2342 width=1998)"
" Filter: ((base_service_id = 721) AND (((initiated_data -> 'application_form_attributes'::text) ->> '5734'::text) = '9898989822'::text))"

Now problem is that this index is not being used in searching. Rather a sequential scan is being used as described in EXPLAIN.

2 Answers 2

1

You can rewrite your query to use the @> operator which can make use of a GIN index:

select * 
from mytable 
where data->'application_form_attributes' @> '{"5705", "ABCD"}';

That should make use of the following index:

create index on mytable using gin ((data->'application_form_attributes'));

If you always include the base_service_id column in the WHERE clause, you can create a combined index:

create index on mytable 
    using gin (base_service_id , (data->'application_form_attributes'));

The above requires the btree-gin extension.

1

You get that error because data->'application_form_attributes' is too large to fit in an index entry.

You'd have to index the whole left side of the expression:

CREATE INDEX ON mytable (data->'application_form_attributes'->>'5705');

Of course, if '5705' is not a constant, that won't get you far.

With your index, you could change the query to:

... WHERE data->'application_form_attributes' ? '5705'

but since you cannot create the index, that won't help you.

I don't think that there is an easy way out. Perhaps it would be best to "normalize" the schema, pull those values you want to search for out of the JSON and model it as several tables with foreign key relationship. Then your query will be simpler and perform better, and indexing won't be a problem.

8
  • @Laurentz Albe I have a lot of attributes value (not only 5705), so I have tried this using md5 hash: CREATE INDEX myindex1 ON mytable USING btree (base_service_id, md5(data :: jsonb->'application_form_attributes')); Index got created. But now, my search is not using index, it is only doing sequential search on Production server where data is too much. Whereas on my staging server (with of course less data) this index is being used in searching. Unable to know where I am doing wrong.
    – erTugRul
    Commented May 4, 2020 at 12:19
  • Hard to say without EXPLAIN (ANALYZE, BUFFERS output. Commented May 4, 2020 at 12:23
  • Since data is too much, unable to get EXPLAIN result.
    – erTugRul
    Commented May 4, 2020 at 12:24
  • I told you the index you should create. Do you have any problems with the index I suggested? Commented May 4, 2020 at 13:29
  • Should I create that index if application_form_attributes have a lot of values (not only 5705)? I thought this index is for the value 5705.
    – erTugRul
    Commented May 4, 2020 at 14:22

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.