JavaRush /Курсы /SQL SELF /Индексирование массивов: создание GIN- и BTREE-индексов

Индексирование массивов: создание GIN- и BTREE-индексов

SQL SELF
36 уровень , 2 лекция
Открыта

Представьте, что у вас есть таблица с миллионами записей, и один из столбцов хранит массивы. Например, у нас есть таблица products, и каждый продукт может относиться к нескольким категориям:

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name TEXT,
    categories TEXT[] -- Массив строк для хранения категорий продукта
);

Допустим, вы хотите найти все продукты, относящиеся к категории electronics. Простое использование оператора @> для поиска может привести к полному сканированию всей таблицы:

SELECT *
FROM products 
WHERE categories @> ARRAY['electronics'];

Полное сканирование (Seq Scan) — это медленно. Особенно, если таблица огромная. Индексы приходят на помощь, чтобы преобразовать это в более быстрый поиск.

Типы индексов для массивов

PostgreSQL поддерживает два основных типа индексов, которые можно использовать для массивов:

  1. GIN (Generalized Inverted Index) — идеален для поиска, если нужно быстро искать элементы в массиве или проверять пересечения.
  2. BTREE (Binary Tree) — подходит для других операций, например для точного сравнения массивов.

Разберем каждый из них подробнее.

  1. Индекс GIN: со скоростью света

GIN (Generalized Inverted Index) — это индекс, который отлично подходит для работы с операторами, такими как:

  • @> (массив включает элемент или другой массив),
  • <@ (массив включён в другой массив),
  • && (массивы пересекаются).

Вот как можно создать GIN-индекс для нашего столбца categories:

CREATE INDEX idx_categories_gin
ON products USING gin(categories);

После создания индекса выполнение запросов станет заметно быстрее. Например, запрос:

SELECT *
FROM products 
WHERE categories @> ARRAY['electronics'];

будет использовать ваш GIN-индекс.

Забавный факт: GIN индекс работает по принципу инвертированного списка — он хранит, какие элементы (например, строки) находятся в каких записях. Это похоже на обратный указатель, который вы видите в книгах, чтобы найти тему по номеру страницы. Удобно, правда?

  1. Индекс BTREE: когда важен порядок

BTREE (Binary Tree) — это стандартный индекс, который используется в большинстве баз данных. Он подходит для операций, требующих точного сравнения массивов, например:

  • Проверка равенства массива =,
  • Сравнение массивов по порядку элементов (>, <).

Создать BTREE-индекс для массива можно следующим образом:

CREATE INDEX idx_categories_btree
ON products USING btree(categories);

Пример запроса, который может использовать BTREE-индекс:

SELECT *
FROM products
WHERE categories = ARRAY['electronics', 'gadgets'];

Однако стоит помнить, что BTREE-индексы не подходят для операторов вроде @> или <@. Для них лучше использовать GIN.

Примеры использования индексов

Теперь давайте объединим теорию с практикой и разберем несколько примеров.

  1. Поиск пересечения массивов

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

SELECT *
FROM products
WHERE categories && ARRAY['electronics', 'smartphones'];

Для этого идеально подойдет GIN-индекс, который вы уже создали ранее:

CREATE INDEX idx_categories_gin
ON products USING gin(categories);

С таким индексом запрос выполнится значительно быстрее за счет использования инвертированного списка.

  1. Сравнение массивов на равенство

Если вам нужно найти продукты, которые принадлежат только категориям electronics и gadgets (в таком порядке), то здесь лучше использовать BTREE-индекс:

SELECT *
FROM products
WHERE categories = ARRAY['electronics', 'gadgets'];

Создайте соответствующий индекс:

CREATE INDEX idx_categories_btree
ON products USING btree(categories);

Производительность индексов

Индексы помогают ускорять запросы, но их использование имеет и обратную сторону. Например:

  • Создание индекса занимает время и ресурсы. Если у вас очень большая таблица, построение индекса может быть достаточно долгим процессом.
  • Обновление таблицы. Каждый раз, когда вы вставляете новые строки или обновляете существующие данные, индексы тоже обновляются. Это может замедлить операции INSERT и UPDATE.

Однако, в большинстве случаев выгода от быстрого выполнения запросов превышает эти издержки.

Как выбрать: GIN или BTREE?

Вот небольшая таблица, которая поможет вам выбрать подходящий индекс для задач:

Тип операции Рекомендуемый индекс
Поиск пересечения массивов (&&) GIN
Проверка включения (@>, <@) GIN
Проверка равенства (=) BTREE
Сравнение массивов (>, <) BTREE
2
Задача
SQL SELF, 36 уровень, 2 лекция
Недоступна
Создание GIN-индекса для поиска в массиве
Создание GIN-индекса для поиска в массиве
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Евгений Уровень 49 Expert
25 сентября 2025
Сравнение массивов при помощи стандартных операторов >, < происходит следующим образом: элементы массивов попарно до тех пор, пока следующий элемент в одном из массивов не окажется больше другого элемента из второго массива.

SELECT ARRAY [2, 1, 3] > ARRAY [2, 1, 1, 4];
Пример выше возвращает true. Сравнение там такое: 1. 2 = 2 2. 1 = 1 3. 3 > 1 Следовательно, первый массив больше второго.