PostgreSQL: В каких случаях индекс по jsonb_path_ops работает быстрее, чем обычный jsonb_ops при поиске по вложенным ключам?

В PostgreSQL для индексирования колонок типа JSONB доступны два класса операторов GIN-индекса: jsonb_ops (по умолчанию) и jsonb_path_ops. Они принципиально отличаются по структуре хранения и, соответственно, по производительности в разных сценариях.

## Как устроены индексы

**jsonb_ops** индексирует каждый ключ, значение и путь отдельно. Это позволяет использовать операторы `?`, `?|`, `?&` (проверка существования ключей) и `@>` (вхождение). Размер индекса при этом значительно больше.

**jsonb_path_ops** индексирует только пары «путь → значение» в виде хэша. Он поддерживает исключительно оператор `@>`, но делает это значительно эффективнее при работе с вложенными структурами.

## Когда jsonb_path_ops работает быстрее

### 1. Поиск по глубоко вложенным ключам
При запросах вида `data @> ‘{«user»: {«address»: {«city»: «Moscow»}}}’` jsonb_path_ops хэширует весь путь целиком. Это уменьшает количество элементов в индексе и снижает вероятность ложных срабатываний (false positives) при сканировании.

### 2. Высокая кардинальность значений
Когда значения в JSONB уникальны или почти уникальны (например, UUID, email, идентификаторы), хэш пути+значения в jsonb_path_ops даёт очень точную выборку из индекса, минимизируя heap-обращения.

### 3. Большие JSONB-документы с множеством ключей
Чем больше ключей в документе, тем больше записей создаёт jsonb_ops. jsonb_path_ops создаёт меньше записей на документ, что ускоряет как построение индекса, так и поиск.

### 4. Запросы только с оператором @>
Если в приложении используется исключительно оператор вхождения `@>` (containment), jsonb_path_ops — очевидный выбор: он оптимизирован именно под него.

## Когда jsonb_ops предпочтительнее

— Нужны операторы `?`, `?|`, `?&` — проверка существования ключей.
— Поиск по ключам верхнего уровня без значений.
— Требуется поддержка оператора `@?` и `@@` (jsonpath).

## Практический пример

sql
— jsonb_path_ops: меньший индекс, быстрее для @>
CREATE INDEX idx_path ON orders USING GIN (data jsonb_path_ops);

— Эффективный запрос:
SELECT * FROM orders WHERE data @> ‘{«customer»: {«region»: {«code»: «RU»}}}’;

## Итог

jsonb_path_ops выигрывает в размере (обычно на 20–50% меньше) и скорости поиска при использовании `@>` на вложенных структурах. Если ваш основной паттерн — containment-запросы к сложным JSON-документам, jsonb_path_ops является предпочтительным выбором.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.