Материалы / Истории / Частичный индекс для редких значений
История

Частичный индекс для редких значений

История о компактном partial index для редкого активного статуса в таблице с сотнями миллионов завершённых операций.

Лена, ведущий аналитик, уже час смотрела в монитор, как в бездну.

— Макс, это парадокс, — сказала она, когда Макс подошёл с неизменной кружкой кофе. — Я построила индекс, чтобы ускорить поиск. А он замедлил всё. Вставку. Обновление. И даже сам поиск.

Макс молча взглянул на её экран. Таблица operations, 500 миллионов строк. Индекс по полю status, занимающий 25 гигабайт.

— Какой статус ты ищешь? — спросил он, хотя уже знал ответ.

active, — выдохнула Лена. — Но их там доли процента. Остальные 99.9% — это completed.

Макс кивнул. Он сделал глоток кофе и посмотрел на Лену. Не как на коллегу, а как на соучастника фундаментального заблуждения.

— Ты ищешь иголку в стоге сена. Тогда зачем ты индексируешь сено?

Лена моргнула. Вопрос был настолько простым, что казался абсурдным.

— Но… индекс работает по всей колонке. Так устроены базы данных.

— Так устроен мир по умолчанию, — поправил Макс. — Мир, который пытается быть справедливым ко всем и в итоге неэффективен ни для кого. Твой индекс — это огромная, подробная карта города, где отмечен каждый дом. Но ты каждый день ходишь только в одно здание. Зачем тебе карта всего города? Тебе нужен прямой, короткий путь к единственной нужной двери.

Он придвинул её клавиатуру. Пальцы легко пробежали по клавишам.

— Мы не будем составлять карту для всех. Мы создадим её только для избранных.

CREATE INDEX idx_operations_only_active
ON operations (created_at DESC)
WHERE status = 'active';

— Этот индекс, — Макс показал на экран, — содержит только активные строки и сразу поддерживает сортировку дашборда по времени. Хранить status как ключ бессмысленно: внутри partial index он всегда равен одной и той же константе. Если дашборд ищет активную операцию по другому полю, именно это поле и нужно поставить в ключ.

— И ещё одно условие: запрос должен содержать предикат, из которого планировщик может вывести status = 'active'. Параметризованное или логически иначе записанное условие не всегда совпадёт с предикатом индекса на этапе планирования.

Он нажал Enter. После того как команда выполнилась Макс бросил взгляд на статистику:

  • Старый индекс: 25 Гб 🔴

  • Новый индекс: 100 Мб 🟢

— Обнови свой дашборд, — тихо сказал Макс.

Лена нажала F5. Графики, которые раньше вырисовывались несколько секунд, появились раньше, чем она успела убрать палец с клавиши.

Она молчала.

Макс допил кофе и улыбнулся.

— Иногда лучшее решение — не общее, а специализированное. Перестань строить дороги для всех. Проложи одну идеальную тропу туда, куда действительно часто ходишь.