postgresql запрос массива jsonb с использованием индекса джина - PullRequest
0 голосов
/ 26 марта 2020

Использование postgresql 10.6. У меня есть таблица с именем place с полем jsonb towns , которое содержит массив json. Я создал индекс джин по городам. массив json будет иметь десятки тысяч записей. Мне нужно запросить этот массив для 5000 названия города в предложении, где. В запросе обязательно должен использоваться индекс джина для повышения производительности. Мой пример запроса в приведенной ниже скрипте не использует индекс, насколько я видел в плане выполнения. Как этот запрос должен быть написан для использования индекса, чтобы он выполнялся быстро.

Определение таблицы:

CREATE TABLE place (       
    cities jsonb NULL   
);

CREATE INDEX "IX_place_cities" ON place USING gin (cities);

INSERT INTO place
(cities)
VALUES('[{"name": "paris", "continent": "europe"},
{"name": "london", "continent": "europe"},
{"name": "berlin", "continent": "europe"},
{"name": "istanbul", "continent": "europe"},
{"name": "prag", "continent": "europe"},
{"name": "rome", "continent": "europe"},
{"name": "wien", "continent": "europe"},
{"name": "tokyo", "continent": "asia"},
{"name": "beijing", "continent": "asia"},
{"name": "dakar", "continent": "africa"},
{"name": "daresselam", "continent": "africa"},
{"name": "kuala lumpur", "continent": "asia"},
{"name": "barcelona", "continent": "europe"}]');

Мой запрос:

select elems.arrayitem
FROM (
  select jsonb_array_elements(place.cities) as arrayitem 
  from place
) as elems
where elems.arrayitem @> '{"name": "paris"}' 
   or elems.arrayitem @> '{"name": "dakar"}'

SQLFiddle

1 Ответ

2 голосов
/ 26 марта 2020

Как только вы удалите JSON, вы больше не сможете использовать индекс. Я думаю, что вы ищете:

select jsonb_array_elements(p.cities) item
from place p
where p.cities @> '[{"name": "paris"}]'
   or p.cities @> '[{"name": "dakar"}]' 

Или более точно:

select e.item
from place p
   cross join jsonb_array_elements(p.cities) as e(item)
where p.cities @> '[{"name": "paris"}]'
   or p.cities @> '[{"name": "dakar"}]' 

Индекс GIN будет использоваться только в том случае, если в таблице много строк ( нет) элементов в массиве!) И ваше условие WHERE сокращает количество строк до нескольких.

Если вы храните все в одном гигантском JSON значении в одной строке, ни один индекс не улучшит ваш запрос. Вместо этого вам следует нормализовать модель данных - что кажется довольно простым делом, поскольку у вас нет динамической структуры c и все элементы имеют одинаковые ключи (= столбец).

...