In a Postgres 9.4 database, I have a json array with around 1000 elements of the structure:
"oid: aaa, instance:bbb, value:ccc"
Sample:
{"_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
and instance
are unique per json array. If I was given the option to change the structure I would have changed the format to 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 I need to stay with the old structure
What is the fastest way to get specific
oid
from the array?What is the fastest way to get a table with 3 columns of
oid
,instance
andvalue
. Or even better a pivot table with oid+instance as the column header.
For 2. I tried the following, but it was pretty slow on a large table:
select *
from (
select a->>'oid' oid, a->>'instance' instance, a->>'value' value1, id
from (
select jsonb_array_elements(config#>'{data}') a, id
from configuration
) b
) c
where oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3' and instance = '0' and value1 <> '1';
Query
Your table definition is missing. Assuming:
To find the a
value
and its row for givenoid
andinstance
:That's an implicit
LATERAL
join. Compare:I suppose to use
jsonb_populate_recordset()
, then you can provide data types in the table definition. Assumingtext
for all:Can also be a persisted (non-temp) table or view. This one is only for the current session. Then:
That's all. The first query rewritten:
But that's slower than the first query. Key to performance with bigger table is index support:
Index
You could easily index the normalized (translated) table or the alternative layout you proposed in the question. Indexing your current layout is not as obvious, but also possible. For best performance I suggest a functional index on just the
data
key with thejsonb_path_ops
operator class. The manual:This should work wonders for performance:
One might expect that only a complete match for a JSON array element would work, like:
Note the JSON array notation (with enclosing
[]
) of the provided value: that's required.But array elements with a subset of keys work as well:
The hard part is to incorporate your added predicate
value <> '1'
. Care must be taken to apply all predicates to the same array element. You could combine this with the first query:Voilá.
Special index
If your table is huge, index size may be a deciding factor. You could compare performance of this special solution with a functional index:
This function extracts a Postgres array of oid-instance combinations from a given
jsonb
value:We can build a functional index based on this:
And base the query on it:
The idea is that the index should be substantially smaller because it only stores the combined values without keys. The array containment operator
@>
itself should perform similar to the jsonb containment operator@>
. I don't expect a big difference, but I would be very interested which is faster.Similar to the first solution in this related answer (but more specialized):
Asides
oid
as column name. It's in use for internal purposes in Postgres.