Ответ
При проектировании составных (композитных) индексов в SQL-базах данных я руководствуюсь следующими правилами:
-
Порядок столбцов (самое важное): Индекс работает по принципу левого префикса. Запрос может использовать индекс, только если условие
WHERE,ORDER BYилиJOINвключает столбцы с начала индекса.- Первым должен идти наиболее селективный столбец (с наибольшим количеством уникальных значений).
- Пример: Для запроса
SELECT * FROM orders WHERE user_id = 123 AND status = 'shipped'оптимален индекс(user_id, status), а не(status, user_id), так какuser_idобычно более селективен.
-
Охват запроса (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; -
Условия
WHEREиORDER BY: Если запрос содержит и фильтрацию, и сортировку, порядок столбцов в индексе должен соответствовать: сначала столбцы дляWHERE(по равенству), затем дляORDER BY.-- Оптимальный индекс: (department_id, salary) SELECT * FROM employees WHERE department_id = 10 ORDER BY salary DESC; -
Кардинальность и размер: Слишком длинные индексы (много столбцов или столбцы с большим типом данных, как
TEXT) занимают много памяти и могут замедлять операции вставки/обновления. -
Ограничения СУБД: Нужно знать лимиты своей СУБД (например, максимальная длина индекса в 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 байта. Сделаешь индекс из трёх полей по тысяче байт каждое — и накрылся твой индекс медным тазом, потому что в лимит не влез. Вот такая, блядь, хитрая жопа получается.