sql >> Database >  >> RDS >> PostgreSQL

Postgres 9.4 jsonb-array als tabel

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 en value.

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 een jsonb_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.



  1. Oracle PL/SQL:gegevens uit een tabel exporteren naar CSV

  2. Installeer SQL Server 2019 op een Mac

  3. Bibliotheek niet geladen:/usr/local/opt/readline/lib/libreadline.6.2.dylib

  4. SQL Server 2008 Windows Auth Login Error:De login is van een niet-vertrouwd domein