sql - Postgres 9.4 jsonb array as table -
i have json array around 1000 elements of structure "oid: aaa, instance:bbb, value:ccc".
{"_id": 37637070 , "data": [{"oid": "11.5.15.1.4", "value": "1", "instance": "1.1.4"} , {"oid": "11.5.15.1.9", "value": "17", "instance": "1.1.4"} , {"oid": "12.5.15.1.5", "value": "0.0.0.0", "instance": "0"}]}
oid
, instance
unique per json array. if given option change structure have changed format key:value:
{"11.5.15.1.4-1.1.4":"1", "11.5.15.1.9-1.1.4": "17", "12.5.15.1.5-0": "0.0.0.0"}
however, if need stay old structure
what fastest way specific
oid
array?what fastest way table 3 columns of
oid
,instance
,value
. or better pivot table oid+instance column header.
for 2. tried following, pretty slow on large table:
select * ( select a->>'oid' oid, a->>'instance' instance, a->>'value' value1, id ( select jsonb_array_elements(config#>'{data}') a, id configuration ) b ) c oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3' , instance = '0' , value1 <> '1';
query
your table definition missing. assuming:
create table configuration ( config_id serial primary key , config jsonb not null );
to find value
, row given oid
, instance
:
select c.config_id, d->>'value' value configuration c , jsonb_array_elements(config->'data') d -- default col name "value" d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3' , d->>'instance' = '0' , d->>'value' <> '1'
that's implicit lateral
join. compare:
2) fastest way table 3 columns of
oid
,instance
,value.
i suppose use jsonb_populate_recordset()
, can provide data types in table definition. assuming text
all:
create temp table data_pattern (oid text, value text, instance text);
could persisted (non-temp) table. 1 current session. then:
select c.config_id, d.* configuration c , jsonb_populate_recordset(null::data_pattern, c.config->'data') d
that's all. first query rewritten:
select c.config_id, d.* configuration c , jsonb_populate_recordset(null::data_pattern, c.config->'data') d d.oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3' , d.instance = '0' , d.value <> '1';
but that's slower first query. key performance bigger table index support:
index
you index normalized (translated) table or alternative layout proposed in question. indexing current layout not obvious, possible. best performance suggest functional index on data
key jsonb_path_ops
operator class. per documentation:
the technical difference between
jsonb_ops
,jsonb_path_ops
gin index former creates independent index items each key , value in data, while latter creates index items each value in data.
this should work wonders performance:
create index configuration_my_idx on configuration using gin ((config->'data') jsonb_path_ops);
one might expect complete match json array element work, like:
select * configuration (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3" , "instance": "0", "value": "1234"}]';
note json array notation (with enclosing []
) of provided value, that's required.
but array elements subset of keys work well:
select * configuration (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3" , "instance": "0"}]'
the hard part incorporate seemingly unsuspicious added predicate value <> '1'
. care must taken apply predicates same array element. combine first query:
select c.*, d->>'value' value configuration c , jsonb_array_elements(config->'data') d (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3", "instance": "0"}]' , d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3' -- must repeated , d->>'instance' = '0' -- must repeated , d->>'value' <> '1' -- here can rule out
voilá.
special index
if table huge, index size may deciding factor. compare performance of special solution functional index:
this function extracts postgres array of oid-instance combinations given jsonb
value:
create or replace function f_config_json2arr(_j jsonb) returns text[] language sql immutable $func$ select array( select (elem->>'oid') || '-' || (elem->>'instance') jsonb_array_elements(_j) elem ) $func$
we can build functional index based on this:
create index configuration_conrfig_special_idx on configuration using gin (f_config_json2arr(config->'data'));
and base query on it:
select * configuration f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
the idea index should substantially smaller because stores combined values without keys. array containment operator @>
should perform similar jsonb containment operator @>
. don't expect big difference, interested faster.
similar first solution in related answer (but more specialized):
asides:
- i not use
oid
column name since that's used internal purposes in postgres. - if possible, use plain, normalized table without json.
Comments
Post a Comment