Для поиска по определенным ключам в столбце jsonb
я хотел создать индекс для столбца.
Использование: Postgres 10.2
Игнорируя некоторые несвязанные столбцы, у меня есть таблица animals
с этими столбцами (исключая некоторые несвязанные столбцы):
animalid PK number
location (text)
type (text)
name (text)
data (jsonb) for eg: {"age": 2, "tagid": 11 }
Мне нужно искать на основе: location
, type
и tagId
. Нравиться:
where location = ? and type = 'cat' and (data ->> 'tagid') = ?
Другие важные моменты:
- Только животные типа кошек будут иметь идентификатор метки, это новый тип животных, который добавляется сейчас.
- Количество кошек во всей таблице будет меньше по сравнению с другими видами животных.
- Таблица огромная, с миллионами строк и секционирована.
Как сделать так, чтобы поиск был быстрым? Варианты, которые я рассматривал:
- Сделать отдельную таблицу для хранения котов:
animal_id
,location
,tagId
(хотя FK в партиционированную родительскую таблицу нельзя) - Создайте индекс для
location
,type
и ключа jsonb. - Создайте новый (индексированный) столбец
tagId
, который будет нулевым для всех животных, кроме кошки.
У меня есть индекс для других столбцов в таблице, но я немного запутался в том, как создать индекс, чтобы сделать поиск кошек на основе tagid
быстрым. Какие-либо предложения?
ОБНОВЛЕНИЕ (игнорирование разделов):
(Тестирование на секционированной таблице)
Поэтому я решил использовать вариант, предложенный Эрвином, и попытался создать индекс
CREATE INDEX ON animals_211 (location, ((data->>'tagid')::uuid)) WHERE type = 'cat';
И попробовал EXPLAIN для запроса (используя секционированную таблицу для простоты):
explain select * from animals_211 a
where a.location = 32341
and a.type = 'cat'
and (data->>'tagid')::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'
И судя по результатам, он не использует созданный индекс и выполняет последовательное сканирование:
Seq Scan on animals_211 e (cost=0.00..121.70 rows=1 width=327) |
Filter: ((location = 32341) AND ((type)::text = 'cat'::text) AND (((data ->> 'tagid'::text))::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'::uuid
ОБНОВЛЕНИЕ 2 (без использования частичного индекса)
Это как-то парциальный индекс, как без него - вроде работает:
CREATE INDEX tag_id_index ON animals_211 (location, type, ((data->>'tagid')::uuid))
Когда я делаю план объяснения:
Index Scan using tag_id_index on animals_211 e (cost=0.28..8.30 rows=1 width=327)
Index Cond: ((location = 32341) AND ((type)::text = 'cat'::text) AND (((data ->> 'tagid'::text))::uuid = '5e54c1d9-3ea0-4bca-81d6-1000d90cc42c'::uuid))
ANALYZE
. Рассмотрим примечания и ссылки, которые я добавил к своему ответу. - person Erwin Brandstetter   schedule 03.02.2021