sql >> Databáze >  >> RDS >> PostgreSQL

Pole jsonb Postgres 9.4 jako tabulka

Dotaz

Chybí definice vaší tabulky. Za předpokladu:

CREATE TABLE configuration (
  config_id serial PRIMARY KEY
, config jsonb NOT NULL
);

Chcete-li najít value a jeho řádek pro daný oid a 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'

To je implicitní LATERAL připojit. Porovnejte:

  • Dotaz na prvky pole v typu JSON

2) Jaký je nejrychlejší způsob, jak získat tabulku se 3 sloupci oid , instance a value.

Předpokládám, že použiji jsonb_populate_recordset() , pak můžete v definici tabulky zadat datové typy. Za předpokladu text pro všechny:

CREATE TEMP TABLE data_pattern (oid text, value text, instance text);

Může to být také trvalá (nedočasná) tabulka. Toto je pouze pro aktuální relaci. Potom:

SELECT c.config_id, d.*
FROM   configuration c
     , jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d

To je vše. První přepsaný dotaz:

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';

Ale to je pomalejší než první dotaz. Klíčem k výkonu s větší tabulkou je podpora indexů:

Index

Můžete snadno indexovat normalizovanou (přeloženou) tabulku nebo alternativní rozložení, které jste navrhli v otázce. Indexování aktuálního rozvržení není tak zřejmé, ale také možné. Pro nejlepší výkon navrhuji funkční index pouze na data klíč pomocí jsonb_path_ops třída operátorů. Podle dokumentace:

Technický rozdíl mezi jsonb_ops a jsonb_path_ops GINindex spočívá v tom, že první vytváří nezávislé položky indexu pro každý klíč a hodnotu v datech, zatímco druhý vytváří položky indexu pouze pro každou hodnotu v datech.

To by mělo dělat zázraky pro výkon:

CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);

Dalo by se očekávat, že bude fungovat pouze úplná shoda pro prvek pole JSON, například:

SELECT * FROM configuration
WHERE  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
                            , "instance": "0", "value": "1234"}]';

Všimněte si zápisu pole JSON (s uzavřením [] ) poskytnuté hodnoty, to je povinné.

Ale prvky pole s podmnožinou klíčů pracovat také:

SELECT * FROM configuration
WHERE  (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
                            , "instance": "0"}]'

Nejtěžší je začlenit váš zdánlivě nepodezřelý přidaný predikát value <> '1' . Je třeba dbát na to, aby všechny predikáty byly stejné prvek pole. Můžete to zkombinovat s prvním dotazem:

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á.

Speciální index

Pokud je váš stůl obrovský, může být rozhodujícím faktorem velikost indexu. Výkon tohoto speciálního řešení můžete porovnat s funkčním indexem:

Tato funkce extrahuje pole Postgres oid-instance kombinace z daného jsonb hodnota:

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$

Na základě toho můžeme sestavit funkční index:

CREATE INDEX configuration_conrfig_special_idx ON configuration
USING  gin (f_config_json2arr(config->'data'));

A založte na tom dotaz:

SELECT * FROM configuration
WHERE  f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]

Myšlenka je taková, že index by měl být podstatně menší, protože ukládá pouze kombinované hodnoty bez klíčů. Pole operátor kontejnmentu @> sám by měl fungovat podobně jako operátor kontejnmentu jsonb @> . Nečekám velký rozdíl, ale velmi by mě zajímalo, který je rychlejší.

Podobné jako první řešení v této související odpovědi (ale více specializované):

  • Index pro nalezení prvku v poli JSON

Asides:

  • Nepoužil bych oid jako název sloupce, protože se také používá pro interní účely v Postgres.
  • Pokud je to možné, použil bych obyčejnou normalizovanou tabulku bez JSON.



  1. Chyba při použití připojení OLAP:Poskytovatel MSOLAP není registrován na místním počítači...

  2. Redundantní data v aktualizačních výpisech

  3. Jak zkomprimovat a opravit databázi automaticky v Accessu 2016

  4. lepší přístup než ukládání hesla mysql v prostém textu v konfiguračním souboru?