Запитване
Вашата таблица липсва. Ако приемем:
CREATE TABLE configuration (
config_id serial PRIMARY KEY
, config jsonb NOT NULL
);
За да намерите value
и неговия ред за даден oid
и 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'
Това е имплицитно LATERAL
присъединяване. Сравнете:
- Запитване за елементи на масив в JSON тип
2) Кой е най-бързият начин да получите таблица с 3 колони
oid
,instance
иvalue.
Предполагам да използвам jsonb_populate_recordset()
, тогава можете да предоставите типове данни в дефиницията на таблицата. Приемаме text
за всички:
CREATE TEMP TABLE data_pattern (oid text, value text, instance text);
Може също да е постоянна (не-температурна) таблица. Това е само за текущата сесия. След това:
SELECT c.config_id, d.*
FROM configuration c
, jsonb_populate_recordset(NULL::data_pattern, c.config->'data') d
Това е всичко. Първата заявка е пренаписана:
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';
Но това е по-бавно отколкото първата заявка. Ключът към производителността с по-голяма таблица е поддръжката на индекси:
Индекс
Можете лесно да индексирате нормализираната (преведена) таблица или алтернативното оформление, което сте предложили във въпроса. Индексиране на вашето текущо оформление не е толкова очевидно, но също е възможно. За най-добра производителност предлагам функционален индекс само за data
ключ с jsonb_path_ops
оператор клас. По документация:
Техническата разлика между
jsonb_ops
иjsonb_path_ops
GINindex е, че първият създава независими индексни елементи за всеки ключ и стойност в данните, докато вторият създава индексни елементи само за всяка стойност в данните.
Това трябва да направи чудеса за изпълнение:
CREATE INDEX configuration_my_idx ON configuration
USING gin ((config->'data') jsonb_path_ops);
Може да се очаква, че само пълно съвпадение за елемент на JSON масив ще работи, като:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0", "value": "1234"}]';
Обърнете внимание на нотацията на JSON масива (с ограждащ []
) от предоставената стойност, това е задължително.
Но елементи на масив сподмножество от ключове работи също така:
SELECT * FROM configuration
WHERE (config->'data') @> '[{"oid": "1.3.6.1.4.1.7352.3.10.2.5.35.3"
, "instance": "0"}]'
Трудната част е да включите вашия привидно неподозрителен добавен предикат value <> '1'
. Трябва да се внимава да се прилагат всички предикати към същите елемент на масива. Можете да комбинирате това с първата заявка:
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
Авоа.
Специален индекс
Ако вашата таблица е огромна, размерът на индекса може да бъде решаващ фактор. Можете да сравните производителността на това специално решение с функционален индекс:
Тази функция извлича Postgres масив от oid-instance комбинации от даден jsonb
стойност:
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$
Можем да изградим функционален индекс въз основа на това:
CREATE INDEX configuration_conrfig_special_idx ON configuration
USING gin (f_config_json2arr(config->'data'));
И базирайте заявката на него:
SELECT * FROM configuration
WHERE f_config_json2arr(config->'data') @> '{1.3.6.1.4.1.7352.3.10.2.5.35.3-0}'::text[]
Идеята е, че индексът трябва да бъде значително по-малък, защото съхранява само комбинираните стойности без ключове. Масивът оператор за ограничаване @>
самият той трябва да работи подобно на оператора за задържане на jsonb @>
. Не очаквам голяма разлика, но бих се интересувал кое е по-бързо.
Подобно на първото решение в този свързан отговор (но по-специализирано):
- Индекс за намиране на елемент в JSON масив
Отстрани:
- Не бих използвал
oid
като име на колона, тъй като се използва и за вътрешни цели в Postgres. - Ако е възможно, бих използвал обикновена, нормализирана таблица без JSON.