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
avalue.
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
ajsonb_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.