12.9. Типы индексов GiST и GIN

Для ускорения полнотекстового поиска можно использовать индексы двух видов. Заметьте, что эти индексы не требуются для поиска, но если по какой-то колонке поиск выполняется регулярно, обычно желательно её индексировать.

CREATE INDEX имя ON таблица USING gist(колонка);

Создаёт индекс на базе GiST (Generalized Search Tree, Обобщённое дерево поиска). Здесь колонка может иметь тип tsvector или tsquery.

CREATE INDEX имя ON таблица USING gin(колонка);

Создаёт индекс на базе GIN (Generalized Inverted Index, Обобщённый Инвертированный Индекс). Колонка должна иметь тип tsvector.

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

Индекс GiST допускает неточности, то есть он допускает ложные попадания и поэтому их нужно исключать дополнительно, сверяя результат с фактическими данными таблицы. (PostgreSQL делает это автоматически.) Индексы GiST являются неточными, так как все документы в них представляются сигнатурой фиксированной длины. Эта сигнатура создаётся в результате представления присутствия каждого слова как одного бита в строке из n-бит, а затем логического объединения этих битовых строк. Если двум словам будет соответствовать одна битовая позиция, попадание оказывается ложным. Если для всех слов оказались установлены соответствующие биты (в случае фактического или ложного попадания), для проверки правильности предположения о совпадении слов необходимо прочитать строку таблицы.

Неточность индекса приводит к снижению производительности из-за дополнительных обращений к записям таблицы, для которых предположение о совпадении оказывается ложным. Так как произвольный доступ к таблице обычно не бывает быстрым, это ограничивает применимость индексов GiST. Вероятность ложных попаданий зависит от ряда факторов, например от количества уникальных слов, так что его рекомендуется сокращать, применяя словари.

Индексы GIN не являются неточными для стандартных запросов, но их производительность логарифмически зависит от числа уникальных слов. (Однако индексы GIN хранят только слова (лексемы) значений tsvector, но теряют информацию об их весах. Таким образом для выполнения запроса с весами потребуется перепроверить данные в таблице.)

Выбирая между индексами GiST и GIN, учтите следующие их отличия с точки зрения производительности:

  • Поиск по индексу GIN примерно втрое быстрее, чем по GiST

  • Индексы GIN строятся примерно втрое дольше, чем GiST

  • Индексы GIN обновляются несколько медленнее, чем GiST, но если отключено быстрое обновление (см. Подраздел 58.4.1) разница может достигать 10 раз

  • Индексы GIN обычно в два-три раза больше индексов GiST

Как правило, индексы GIN лучше подходят для статических данных, так как поиск с ними выполняется быстрее. Для динамических данных лучше использовать индексы GiST, так как они быстрее обновляются. Точнее, индексы GiST очень хороши для динамических данных и работают быстро, если число уникальных слов (лексем) не превышает 100 000, а GIN лучше справятся с большим количеством лексем, но обновляться будут медленнее.

Заметьте, что построение индекса GIN часто можно ускорить, увеличив maintenance_work_mem, тогда как время построения индекса GiST не зависит от этого параметра.

Есть два направления увеличения скорости поиска с возможностью обновления «на лету»: секционировать большие коллекции документов и эффективно применять индексы GiST и GIN. Секционировать данные можно как на уровне базы, с использованием наследования таблиц, так и распределив документы по разным серверам и затем собирая результаты с помощью модуля dblink. Последний вариант возможен благодаря тому, что функции ранжирования используют только локальную информацию.