Что такое условный (частичный) индекс в SQL и как его создать?

Ответ

Условный индекс (Partial/Filtered Index) — это индекс, построенный только для подмножества строк таблицы, удовлетворяющих заданному условию WHERE. Это уменьшает размер индекса и ускоряет запросы, которые используют это же условие.

Создание в PostgreSQL:

-- Индекс только для активных заказов
CREATE INDEX idx_orders_active ON orders (customer_id, created_at)
WHERE status = 'ACTIVE';

-- Индекс для не удаленных записей
CREATE INDEX idx_users_not_deleted ON users (email)
WHERE deleted_at IS NULL;

Особенности и best practices:

  • Производительность: Индекс меньше по размеру, быстрее строится и обновляется.
  • Использование: Оптимизатор СУБД сможет использовать индекс только если условие в запросе логически влечет условие индекса. Например, индекс WHERE status = 'ACTIVE' не будет использован для запроса WHERE status IN ('ACTIVE', 'PENDING').
  • Поддержка СУБД:
    • PostgreSQL, SQLite: Полная поддержка.
    • MySQL (8.0+): Поддерживаются как Functional Indexes, которые можно использовать для той же цели.
      -- Пример в MySQL 8.0
      CREATE INDEX idx_status ON orders ((1)) WHERE status = 'ACTIVE';
    • SQL Server: Использует Filtered Indexes.
  • В JPA: Прямого создания через аннотации нет. Условные индексы создаются с помощью нативных SQL-скриптов в инструментах миграции (Flyway, Liquibase).

Ответ 18+ 🔞

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

Короче, что это такое? Это индекс, который строится не на всю таблицу, а только на часть строк, которые проходят по фильтру. Типа, «индексируем только то, что реально часто ищем». Размер меньше, скорость выше — красота, ебать мои старые костыли!

Как его слепить в PostgreSQL:

-- Допустим, тебе постоянно нужно искать активные заказы по клиенту и дате.
-- Зачем индексировать все миллионы отменённых и доставленных? Бред же!
CREATE INDEX idx_orders_active ON orders (customer_id, created_at)
WHERE status = 'ACTIVE';

-- Или классика: индексируем только живых юзеров, а удалённых — нахуй не надо.
CREATE INDEX idx_users_not_deleted ON users (email)
WHERE deleted_at IS NULL;

А теперь подводные ебучки и важные фишки:

  • Выгода: Индекс легковесный, строится быстрее, меньше жрёт места на диске и при обновлении данных не так грузит систему. Овердохуища пользы!
  • Главный нюанс, блядь! Оптимизатор — хитрая жопа. Он использует этот индекс только если твой запрос логически следует условию индекса. Вот пример: если у тебя индекс WHERE status = 'ACTIVE', а ты в запросе ищешь WHERE status IN ('ACTIVE', 'PENDING') — всё, поезд ушёл, индекс проигнорируют. Он же не для пендингов, ёпта!
  • Где что поддерживается:
    • PostgreSQL, SQLite: Тут всё чётко, полная поддержка, как в аптеке.
    • MySQL (начиная с 8.0): Прямых условных индексов нет, но есть Functional Indexes, которыми можно выебать систему и добиться того же. Смотри:
      -- Это типа как условный индекс в MySQL
      CREATE INDEX idx_status ON orders ((1)) WHERE status = 'ACTIVE';
    • SQL Server: Там это называется Filtered Indexes, суть та же.
  • А как в JPA/Hibernate это сделать? Да нихуя не сделать, вот в чём прикол! Стандартные аннотации этого не умеют. Придётся лезть в миграционные скрипты (Flyway, Liquibase) и там уже нативными SQL-запросчиками этот индекс и создавать. JPA тут просто разводит руками, мол, «это не моя епархия, чувак».

В общем, штука мощная, но требующая аккуратности. Как скальпель: если применять к месту — спасёт жизнь, а если тыкать куда попало — можно и пиздец натворить.