Индексирование только атрибута в массиве json - Postgres - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть таблица с полем jsonb с именем «data» со следующим содержимым:

{
  customerId: 1,
  something: "..."
  list: [{ nestedId: 1, attribute: "a" }, { nestedId: 2, attribute: "b" }]
}

Мне нужно извлечь всю строку на основе ее атрибута nestedId, обратите внимание, что поле находится внутри массив.

После проверки планов запросов я обнаружил, что могу извлечь выгоду из индекса. Поэтому я добавил:

CREATE INDEX i1 ON mytable using gin ((data->'list') jsonb_path_ops))

Из того, что я понял из do c, это создает элементы индекса для значений в «списке», решение решает мою проблему.

Для ради завершения следуйте запросу, который я могу использовать для извлечения моих данных

SELECT data FROM mytable where data->'list' @> '[{"nestedId": 1}]'

То есть мне интересно, можно ли было бы сделать более оптимальную индексацию. Можно ли создать индекс только для поля "nestedId", например?

1 Ответ

0 голосов
/ 14 февраля 2020

Вы можете индексировать только числовые значения c, а не ключи, используя функциональные индексы. Вам, вероятно, нужно сделать вспомогательную функцию, чтобы сделать это.

create function jsonb_objarray_to_intarray(jsonb,text) returns int[] immutable language sql as 
  $$ select array_agg((x->>$2)::int) from jsonb_array_elements($1) f(x) $$;

create index on mytable using gin (jsonb_objarray_to_intarray(data->'list','nestedId'));

SELECT data FROM mytable where jsonb_objarray_to_intarray(data->'list','nestedId') @> ARRAY[3];

Я написал это таким образом, чтобы функцию можно было повторно использовать в других подобных ситуациях. Если вас не волнует повторное использование, вы можете сделать код, который его использует, красивее, жестко закодировав разыменование и значение ключа в функции:

create function mytable_to_intarray(jsonb) returns int[] immutable language sql as 
  $$ select array_agg((x->>'nestedId')::int) from jsonb_array_elements($1->'list') f(x) $$;

create index on mytable using gin (mytable_to_intarray(data));

SELECT data FROM mytable where mytable_to_intarray(data) @> ARRAY[3];

Теперь эти индексы принимают дольше, чем ваш оригинал, но они примерно вдвое меньше по размеру и по крайней мере так же быстро делают запросы. Что еще более важно, у планировщика есть лучшая статистика по избирательности, и поэтому при более сложных запросах, вероятно, придут лучшие планы запросов.

...