2016-03-18 8 views
14

Использование Postgres 9.4, я хочу создать индекс в столбце json, который будет использоваться при поиске по определенным ключам в столбце.PostgreSQL Index on JSON

Например, у меня есть «фермерская» таблица с «животными» json column.

Колонка животных имеет JSon объекты общего формата:

'{"cow": 2, "chicken": 11, "horse": 3}' 

Я попытался несколько индексов (отдельно):

(1) create INDEX animal_index ON farm ((animal ->> 'cow')); 
(2) create INDEX animal_index ON farm using gin ((animal ->> 'cow')); 
(3) create INDEX animal_index ON farm using gist ((animal ->> 'cow')); 

Я хочу, чтобы выполнять запросы, как:

SELECT * FROM farm WHERE (animal ->> 'cow') > 3; 

и имейте этот запрос, используя индекс.

Когда я запускаю этот запрос:

SELECT * FROM farm WHERE (animal ->> 'cow') is null; 

затем (1) индекс работает, но я не могу получить какой-либо из индексов работать неравенства.

Возможно ли такое изменение?

В таблице фермы содержится только ~ 5000 ферм, но некоторые из них содержат 100 животных и запросы просто слишком долго для моего использования. Индекс, подобный этому, является единственным методом, который я могу придумать для ускорения этого запроса, но, возможно, есть и другой вариант.

ответ

29

Ваши другие два индекса не будет работать просто потому, что ->> operator возвращается text, в то время как вы, очевидно, имеют jsonb джин классы операторов в виду. Обратите внимание, что вы указываете только json, но вам действительно нужно jsonb для расширенных возможностей индексирования.

Чтобы разработать лучшую стратегию индексирования, вам нужно будет более точно определить, какие запросы следует покрывать. Вас интересуют только коровы? Или все животные/все теги? Какие операторы возможны? В вашем документе JSON также содержатся ключи от животных? Что с ними делать? Вы хотите включить строки в индекс, где корова (или что-то еще) вообще не отображается в документе JSON?

Предполагая:

  • Мы заинтересованы только в коровах на первом уровне вложенности.
  • Величина всегда действительна integer.
  • Мы не заинтересованы в рядах без коров.

Я предлагаю функциональный индекс btree, как и у вас, но приведение значения к целому. Я не думаю, что вы хотите, чтобы сравнение оценивалось как text (где «2» больше, чем «1111»).

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)); -- ! 

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

Используйте то же самое выражение в запросах, чтобы сделать Postgres реализовать индекс применим:

SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3; 

Если вам нужен более общий jsonb индекс, считают:

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

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)) 
WHERE (animal ->> 'cow') IS NOT NULL; 

CREATE INDEX animal_index ON farm (((animal ->> 'chicken')::int)) 
WHERE (animal ->> 'chicken') IS NOT NULL; 

Etc.

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

SELECT * FROM farm 
WHERE (animal ->> 'cow')::int > 3 
AND (animal ->> 'cow') IS NOT NULL; 

Может показаться излишним, но может потребоваться , Тест с ANALYZE!

+0

Спасибо! Замечательный ответ. Меня интересует только первый уровень. Значение всегда является целым числом. Однако меня интересуют некоторые другие животные. Имеет ли смысл просто копировать этот индекс для каждого интересующего меня животного? – lnhubbell

+0

@lnhubbell: для * известного, статического, тривиального * количества животных это должно быть самым простым и эффективным решением. Однако я бы явно сделал их частичными индексами. См. Добавление выше. –

 Смежные вопросы

  • Нет связанных вопросов^_^