Fråga
Din tabelldefinition saknas. Förutsatt att:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
För att hitta ett value
och dess rad för given oid
och 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 är en implicit LATERAL
Ansluta sig. Jämför:
- Fråga efter arrayelement i JSON-typ
2) Vilket är det snabbaste sättet att få en tabell med 3 kolumner med
oid
,instance
ochvalue.
Jag antar att jag använder jsonb_populate_recordset()
, då kan du ange datatyper i tabelldefinitionen. Förutsatt text
för alla:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
Kan också vara en beständig (icke-temp) tabell. Den här är endast för den aktuella sessionen. Sedan:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
Det är allt. Den första frågan skrevs om:
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 är långsammare än den första frågan. Nyckeln till prestanda med större tabell är indexstöd:
Index
Du kan enkelt indexera den normaliserade (översatta) tabellen eller den alternativa layout du föreslog i frågan. Indexerar din aktuella layout är inte lika självklart, men också möjligt. För bästa prestanda föreslår jag ett funktionsindex på bara data
nyckel med jsonb_path_ops
operatörsklass. Per dokumentation:
Den tekniska skillnaden mellan en
jsonb_ops
och enjsonb_path_ops
GINindex är att den förra skapar oberoende indexposter för varje nyckel och värde i data, medan den senare skapar indexposter endast för varje värde i datan.
Detta bör göra underverk för prestanda:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
Man kan förvänta sig att endast en fullständig matchning för ett JSON-arrayelement skulle fungera, 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"}]';
Observera JSON-arraynotationen (med omslutande []
) av det angivna värdet, som krävs.
Men matriselement med en underuppsättning av nycklar fungerar också:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
Det svåra är att införliva ditt till synes misstänkta predikat value <> '1'
. Försiktighet måste iakttas för att tillämpa alla predikat på samma arrayelement. Du kan kombinera detta med den första frågan:
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á.
Specialindex
Om ditt bord är stort kan indexstorleken vara en avgörande faktor. Du kan jämföra prestandan för denna speciallösning med ett funktionsindex:
Den här funktionen extraherar en Postgres-array av oid-instans kombinationer från en given jsonb
värde:
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 bygga ett funktionsindex baserat på detta:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
Och basera frågan 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 är att indexet ska vara betydligt mindre eftersom det bara lagrar de kombinerade värdena utan nycklar. matrisen inneslutningsoperatör @>
själv bör fungera liknande jsonb-inneslutningsoperatören @>
. Jag förväntar mig ingen stor skillnad, men jag skulle vara väldigt intresserad vilket är snabbare.
Liknar den första lösningen i detta relaterade svar (men mer specialiserat):
- Index för att hitta ett element i en JSON-array
Förutom:
- Jag skulle inte använda
oid
som kolumnnamn eftersom det också används för interna ändamål i Postgres. - Om möjligt skulle jag använda en vanlig, normaliserad tabell utan JSON.