Может ли PostgreSQL индексировать более глубокие пути в столбцах JSON?

#json #postgresql #indexing

#json #postgresql #индексирование

Вопрос:

Я готовлюсь использовать хранилище json PostgreSQL и функциональность запросов. Я думаю, что я немного понимаю часть вставки и запроса, но я не могу найти пример того, как поддерживать (через индекс) запрос в json path глубиной более одного уровня. Я тестирую со следующим:

 CREATE TABLE orders (
    id serial NOT NULL PRIMARY KEY,
    info json NOT NULL
);

INSERT INTO orders (info)
VALUES('{ "customer": "Mark Stevens", "items": {"product": { "name" : "Phone","qty": 3}}}'),
      ('{ "customer": "Josh William", "items": {"product": { "name" : "Toy Car","qty": 1}}}'),
      ('{ "customer": "Mary Clark", "items": {"product": { "name" : "Toy Train","qty": 2}}}');
  

Это немного сконструированный пример. Суть в том, что поле qty вложено глубиной более одного уровня.

Я могу выполнить запрос по этому запросу для всех записей с кол-вом 1:

 SELECT * FROM orders
WHERE info::jsonb @@ '$.items.product.qty == 1';
  

Все это работает нормально. Протестировано с использованием pgAdmin.
Итак, теперь я хочу определить индекс для поддержки этого запроса (или его версию, которая может поддерживаться индексом, поскольку часто имеет значение способ написания запроса).

Я просматривал здесь и в документации pg, но не увидел примера определения индекса, которое я мог бы превратить в рабочее для этого примера. Кажется, что все примеры охватывают пути только одного уровня. например, если бы кол-во было на один уровень глубже в json, поддерживающий индекс выглядел бы примерно так

 CREATE INDEX orders_index ON orders (((info ->> 'customer')::VARCHAR), ((info #>> '{items, qty}')::INTEGER));
  

Итак, мой вопрос таков: возможно ли создать индекс, поддерживающий мой запрос на более глубоких уровнях json? И если да, может ли кто-нибудь привести мне пример?

Комментарии:

1. postgresql.org/docs/current/datatype-json.html#JSON-INDEXING

Ответ №1:

Вы должны определить столбец jsonb , здесь нет никакого преимущества в использовании json . Следующее предполагает jsonb столбец, а не json колонку

Вы можете определить индекс GIN для столбца:

 create index on orders using gin (info);
  

Или, альтернативно, для немного меньшего и более эффективного индекса:

 create index on orders using gin (info jsonb_path_ops);
  

Затем запрос:

 SELECT * 
FROM orders
WHERE info @@ '$.items.product.qty == 1';
  

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

Альтернативный запрос:

 SELECT * 
FROM orders
WHERE info @> '{"items": {"product" : {"qty": 1}}}'
  

также использовал бы этот индекс.


Вы можете создать меньший (GIN) индекс, если вы знаете, что всегда будете просматривать, например, products часть:

 create index on orders using gin ( (info #> '{items,products}') );
  

Но тогда вам нужно скорректировать свой запрос:

 SELECT * 
FROM orders
WHERE info #> '{items,products}' @@ '$.qty == 1';
  

Вы можете увидеть поддерживаемые операторы JSONB здесь


Если вы всегда хотите запрашивать количество, то, возможно, достаточно индекса B-дерева. Индексы B-дерева меньше индексов GIN, а также имеют меньшие накладные расходы на их обновление.

 create index on orders ( ((info #>> '{items,product,qty}')::int) );
  

Тогда следующий запрос будет использовать этот индекс:

 SELECT * 
FROM orders
WHERE (info #>> '{items,product,qty})::int = 1;
  

Комментарии:

1. Спасибо! Ответ b-tree — это то, что я искал, в сочетании с типом jsonb и наличием достаточного количества записей в таблице, чтобы pg вообще рассматривал возможность использования индекса. Сейчас мой тест работает.