Zoekopdracht
Uw tabeldefinitie ontbreekt. Ervan uitgaande:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
De a value
vinden en zijn rij voor gegeven oid
en instance
:
SELECT c.config_id, d->>'value' AS value
FROM configuration c
, jsonb_array_elements(config->'data') d -- default col name is "value"
WHERE d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3'
AND d->>'instance' = '0'
AND d->>'value' <> '1'
Dat is een impliciete LATERAL
meedoen. Vergelijk:
- Query voor array-elementen binnen het JSON-type
2) Wat is de snelste manier om een tabel te krijgen met 3 kolommen
oid
,instance
envalue.
Ik veronderstel dat ik jsonb_populate_recordset()
. moet gebruiken , dan kunt u gegevenstypen opgeven in de tabeldefinitie. Uitgaande van text
voor iedereen:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
Kan ook een persistente (niet-tijdelijke) tabel zijn. Deze is alleen voor de huidige sessie. Dan:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
Dat is alles. De eerste vraag herschreven:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
WHERE d.oid = '1.3.6.1.4.1.7352.3.10.2.5.35.3'
AND d.instance = '0'
AND d.value <> '1';
Maar dat is langzamer dan de eerste vraag. De sleutel tot prestaties met een grotere tabel is indexondersteuning:
Index
U kunt eenvoudig de genormaliseerde (vertaalde) tabel of de alternatieve lay-out die u in de vraag voorstelt, indexeren. Uw huidige lay-out indexeren niet zo voor de hand liggend, maar ook mogelijk. Voor de beste prestaties raad ik een functionele index aan op alleen de data
sleutel met de jsonb_path_ops
operator klasse. Per documentatie:
Het technische verschil tussen een
jsonb_ops
en eenjsonb_path_ops
GINindex is dat de eerste onafhankelijke indexitems maakt voor elke sleutel en waarde in de gegevens, terwijl de laatste alleen indexitems maakt voor elke waarde in de gegevens.
Dit zou wonderen moeten doen voor prestaties:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
Je zou verwachten dat alleen een volledige match voor een JSON-array-element zou werken, zoals:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0", "value": "1234"}]';
Let op de JSON-arraynotatie (met omsluitende []
) van de opgegeven waarde, dat is vereist.
Maar array-elementen met een subset van sleutels werk ook:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
Het moeilijkste is om je schijnbaar onschuldige toegevoegde predikaat value <> '1'
op te nemen . Er moet voor worden gezorgd dat alle predikaten op dezelfde . worden toegepast array-element. Je zou dit kunnen combineren met de eerste vraag:
SELECT c.*, d->>'value' AS value
FROM configuration c
, jsonb_array_elements(config->'data') d
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3", "instance": "0"}]'
AND d->>'oid' = '1.3.6.1.4.1.7352.3.10.2.5.35.3' -- must be repeated
AND d->>'instance' = '0' -- must be repeated
AND d->>'value' <> '1' -- here we can rule out
Voilá.
Speciale index
Als uw tafel enorm is, kan de indexgrootte een beslissende factor zijn. U kunt de prestaties van deze speciale oplossing vergelijken met een functionele index:
Deze functie extraheert een Postgres-array van oid-instance combinaties van een gegeven jsonb
waarde:
CREATE OR REPLACE FUNCTION f_config_json2arr(_j jsonb)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
$func$
SELECT ARRAY(
SELECT (elem->>'oid') || '-' || (elem->>'instance')
FROM jsonb_array_elements(_j) elem
)
$func$
Op basis hiervan kunnen we een functionele index bouwen:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
En baseer de vraag daarop:
SELECT * FROM configuration
WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
Het idee is dat de index aanzienlijk kleiner zou moeten zijn omdat het alleen de gecombineerde waarden zonder sleutels opslaat. De array insluitingsoperator @>
zelf zou vergelijkbaar moeten zijn met de jsonb-insluitingsoperator @>
. Ik verwacht geen groot verschil, maar ik zou erg geïnteresseerd zijn, wat sneller is.
Vergelijkbaar met de eerste oplossing in dit gerelateerde antwoord (maar meer gespecialiseerd):
- Index voor het vinden van een element in een JSON-array
Terzijdes:
- Ik zou
oid
niet gebruiken als kolomnaam aangezien die ook voor interne doeleinden wordt gebruikt in Postgres. - Indien mogelijk zou ik een gewone, genormaliseerde tabel gebruiken zonder JSON.