PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Postgres 9.4 jsonb масив като таблица

Запитване

Вашата таблица липсва. Ако приемем:

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Функции за дата и час на PostgreSQL

  2. Как Acosh() работи в PostgreSQL

  3. конвертирайте геометричния формат на Postgres в WKT

  4. Как Atand() работи в PostgreSQL

  5. Сравнете масивите за равенство, пренебрегвайки реда на елементите