Forespørgsel
Din tabeldefinition mangler. Forudsat:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
For at finde en value
og dens række for givet oid
og 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'
Det er en implicit LATERAL
tilslutte. Sammenlign:
- Forespørgsel efter array-elementer inde i JSON-typen
2) Hvad er den hurtigste måde at få en tabel med 3 kolonner af oid
, instance
og value.
Jeg formoder at bruge jsonb_populate_recordset()
, så kan du angive datatyper i tabeldefinitionen. Forudsat text
for alle:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
Kan også være et vedvarende (ikke-temp) bord. Denne er kun til den aktuelle session. Så:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
Det er alt. Den første forespørgsel omskrevet:
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';
Men det er langsommere end den første forespørgsel. Nøglen til ydeevne med større tabel er indeksstøtte:
Indeks
Du kan nemt indeksere den normaliserede (oversatte) tabel eller det alternative layout, du foreslog i spørgsmålet. Indeksering af dit aktuelle layout er ikke så indlysende, men også muligt. For den bedste ydeevne foreslår jeg et funktionelt indeks på kun data
tast med jsonb_path_ops
operatørklasse. Per dokumentation:
Den tekniske forskel mellem en jsonb_ops
og en jsonb_path_ops
GINindex er, at førstnævnte opretter uafhængige indekselementer for hver nøgle og værdi i dataene, mens sidstnævnte kun opretter indekselementer for hver værdi i dataene.
Dette skulle gøre underværker for ydeevne:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
Man kunne forvente, at kun et komplet match for et JSON-array-element ville fungere, som:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0", "value": "1234"}]';
Bemærk JSON-array-notationen (med omsluttende []
) af den angivne værdi, som er påkrævet.
Men array-elementer med et undersæt af nøgler arbejde også:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
Den svære del er at inkorporere dit tilsyneladende mistænkelige tilføjede prædikat value <> '1'
. Man skal sørge for at anvende alle prædikater på samme array element. Du kan kombinere dette med den første forespørgsel:
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á.
Særligt indeks
Hvis dit bord er enormt, kan indeksstørrelsen være en afgørende faktor. Du kan sammenligne ydeevnen af denne specielle løsning med et funktionelt indeks:
Denne funktion udtrækker en Postgres-array af oid-instance kombinationer fra en given jsonb
værdi:
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$
Vi kan bygge et funktionelt indeks ud fra dette:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
Og baser forespørgslen på det:
SELECT * FROM configuration
WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
Tanken er, at indekset skal være væsentligt mindre, fordi det kun gemmer de kombinerede værdier uden nøgler. arrayet indeslutningsoperatør @>
i sig selv skal fungere på samme måde som jsonb-indeslutningsoperatøren @>
. Jeg forventer ikke den store forskel, men jeg ville være meget interesseret, hvilket er hurtigere.
Svarende til den første løsning i dette relaterede svar (men mere specialiseret):
- Indeks til at finde et element i et JSON-array
Udover:
- Jeg ville ikke bruge
oid
som kolonnenavn, da det også bruges til interne formål i Postgres. - Hvis det er muligt, ville jeg bruge en almindelig, normaliseret tabel uden JSON.