Какие правила необходимо учитывать при создании составных индексов?

Ответ

При проектировании составных (композитных) индексов в SQL-базах данных я руководствуюсь следующими правилами:

  1. Порядок столбцов (самое важное): Индекс работает по принципу левого префикса. Запрос может использовать индекс, только если условие WHERE, ORDER BY или JOIN включает столбцы с начала индекса.

    • Первым должен идти наиболее селективный столбец (с наибольшим количеством уникальных значений).
    • Пример: Для запроса SELECT * FROM orders WHERE user_id = 123 AND status = 'shipped' оптимален индекс (user_id, status), а не (status, user_id), так как user_id обычно более селективен.
  2. Охват запроса (Covering Index): Если добавить в индекс все столбцы, запрашиваемые в SELECT, база данных может выполнить запрос, обращаясь только к индексу (Index-Only Scan), что значительно ускоряет работу.

    -- Индекс (user_id, created_at) покроет этот запрос
    SELECT user_id, created_at FROM logs WHERE user_id = 5 ORDER BY created_at DESC;
  3. Условия WHERE и ORDER BY: Если запрос содержит и фильтрацию, и сортировку, порядок столбцов в индексе должен соответствовать: сначала столбцы для WHERE (по равенству), затем для ORDER BY.

    -- Оптимальный индекс: (department_id, salary)
    SELECT * FROM employees WHERE department_id = 10 ORDER BY salary DESC;
  4. Кардинальность и размер: Слишком длинные индексы (много столбцов или столбцы с большим типом данных, как TEXT) занимают много памяти и могут замедлять операции вставки/обновления.

  5. Ограничения СУБД: Нужно знать лимиты своей СУБД (например, максимальная длина индекса в MySQL — 3072 байта для InnoDB).

Ответ 18+ 🔞

О, слушай, смотри, я тут про составные индексы в SQL. Это вообще отдельная песня, ёпта. Если накосячить с их порядком — будет тебе вместо скорости тормозовоз, ядрёна вошь.

Вот смотри, главное правило, которое надо вбить себе в башку гвоздём: порядок столбцов — это всё. Индекс работает по принципу левого префикса. Это как если бы ты искал человека в толпе сначала по имени, а потом по фамилии. А если ты начнёшь с фамилии — нихуя не найдёшь, пока всех не переберёшь. Так и тут. Запрос может использовать индекс, только если ты в условии WHERE или ORDER BY цепляешь столбцы с самого начала индекса.

Поэтому первым делом — суёшь в индекс самый селективный столбец. Тот, где значений уникальных дохуя. Например, есть у тебя таблица заказов. Запрос: SELECT * FROM orders WHERE user_id = 123 AND status = 'shipped'. Что поставить первым? user_id, конечно! Потому что юзеров — овердохуища, а статусов — штук пять. Индекс (user_id, status) — огонь. А (status, user_id) — полная хуйня, прости за мой французский. Он сначала будет искать все «отправленные» заказы по всему миру, а потом уже в этой куче искать твоего юзера. Доверия к такому плану — ноль ебать.

Дальше, лайфхак для настоящих ленивых гениев — Covering Index. Суть проста: если ты в SELECT запрашиваешь только те столбцы, которые уже есть в индексе, база данных может вообще не лезть в саму таблицу. Всё сделает прямо по индексу, как по шпаргалке. Это скорость — просто пиздец.

-- Вот смотри, тут мы ищем логи юзера и сортируем по дате.
SELECT user_id, created_at FROM logs WHERE user_id = 5 ORDER BY created_at DESC;

Если сделать индекс (user_id, created_at), то СУБД успокоится, достанет всё оттуда и скажет «всё, свободен». Красота.

Теперь про миксы. Если в запросе у тебя и WHERE есть, и ORDER BY — тут надо думать, э бошка. Правило: сначала в индекс кладёшь столбцы для фильтрации по равенству (WHERE department_id = 10), а уже потом — для сортировки (ORDER BY salary DESC).

-- Идеальный индекс для этого: (department_id, salary)
SELECT * FROM employees WHERE department_id = 10 ORDER BY salary DESC;

Потому что индекс уже отсортирован сначала по отделу, а внутри отдела — по зарплате. База данных просто пройдётся по нужному участку индекса и сразу отдаст тебе данные в правильном порядке. Удивление пиздец, как быстро работает.

Но и тут есть подводные булыжники. Не делай индексы, как маньяк. Слишком длинный индекс — это как таскать с собой полный архив библиотеки вместо одной нужной книги. Жрёт память, тормозит вставку новых записей (их же надо ещё и в индекс воткнуть). Особенно не гонись нахуй с текстовыми полями (TEXT, VARCHAR(100500)). Подумай, оно тебе надо?

И да, не забудь глянуть в мануал своей СУБД. У каждой свои тараканы и лимиты. В том же MySQL для InnoDB, например, максимальная длина индекса — 3072 байта. Сделаешь индекс из трёх полей по тысяче байт каждое — и накрылся твой индекс медным тазом, потому что в лимит не влез. Вот такая, блядь, хитрая жопа получается.