Я довольно новичок в postgres и в настоящее время использую 9.6. При попытке реализовать полнотекстовый поиск в postgres, используя его jsonb-документы, я заметил медленные результаты поиска для вложенных массивов. Я использовал команду «объяснить», и он не использовал никаких индексов. Для простоты цели я создал таблицу для исследования:Индекс для поиска вложенных элементов массива JSONB в PostgreSQL
CREATE TABLE book (
id BIGSERIAL NOT NULL,
data JSONB NOT NULL
);
Моих доступных показателей:
CREATE INDEX book_author_idx
ON book USING GIN (to_tsvector('english', book.data ->> 'author'));
CREATE INDEX book_author_name_idx
ON book USING GIN (to_tsvector('english', book.data -> 'author' ->> 'name'));
И некоторые данные для заполнения документа:
INSERT INTO book (data)
VALUES (CAST('{"author": [{"id": 0, "name": "Cats"}, ' ||
' {"id": 1, "name": "Dogs"}]}' AS JSONB));
Я могу искать для элементов книги, используя следующий запрос, однако он не использует никакого индекса. С моими фактическими данными из 120 тыс. Продуктов он занимает около 1200 мс, в то время как другие поисковые запросы с индексом занимают 0,2 мс.
EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book, jsonb_array_elements(data #> '{author}') author_array
WHERE to_tsvector('english', author_array ->> 'name') @@ to_tsquery('cat');
В отличие от следующего запроса использует book_author_name_idx, но из-за структуры массива не находит ничего.
EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book
WHERE to_tsvector('english', data -> 'author' ->> 'name') @@ to_tsquery('cat');
Как я могу настроить свой запрос на использование указателя языка? Я знаю, что я мог бы создать новую таблицу для авторов и ссылаться только на идентификаторы, но я предпочел бы хранить все данные в одной таблице для повышения производительности.
Использование 'unnest()' и его друзей (функции создания результата, такие как 'jsonb_array_elements()') в 'LATERAL JOIN', предотвращают использование любого индекса (по крайней мере, по свойствам, вычисленным из них). Если вы придерживаетесь этой структуры, вы должны создать пользовательскую функцию 'IMMUTABLE' для создания значений' tsvector' из столбца 'jsonb' и использовать эту функцию в обоих ваших индексах и запросах. – pozs
Интересной частью этого является тот факт, что 'tsvector' не имеет встроенной агрегации, поэтому вам нужно либо: 1) объединить имена в виде строк (с некоторым основным правилом); 2) создать настраиваемую агрегацию для' tsvector' 3) используют умный рекурсивный CTE (поскольку конкатенация уже существует для них). – pozs