Ответ
Составной индекс — это индекс, созданный на несколько столбцов таблицы. Он оптимизирует запросы, которые используют эти столбцы в условиях WHERE, JOIN или ORDER BY.
Ключевой принцип: правило левого префикса (leftmost prefix). Индекс (col1, col2, col3) может быть эффективно использован для запросов с:
col1col1, col2col1, col2, col3
Но НЕ будет эффективен для запросов только с col2 или col3, так как эти столбцы не являются левым префиксом индекса.
Пример создания в SQL:
-- Индекс для ускорения поиска по фамилии и фильтра по возрасту
CREATE INDEX idx_users_lastname_age ON users(last_name, age);
Эффективные запросы для этого индекса:
SELECT * FROM users WHERE last_name = 'Ivanov'; -- Использует префикс индекса
SELECT * FROM users WHERE last_name = 'Ivanov' AND age = 30; -- Использует оба столбца
SELECT * FROM users WHERE last_name = 'Ivanov' ORDER BY age; -- Использует для сортировки
Неэффективный запрос:
SELECT * FROM users WHERE age = 30; -- Полное сканирование, т.к. age не левый префикс
Практические рекомендации:
- Порядок столбцов критичен. Первым ставьте столбец с наибольшей селективностью (уникальностью) или тот, который чаще всего используется в условиях равенства (
=). - В JPA/Hibernate индекс можно задать аннотацией:
@Entity @Table(indexes = @Index(name = "idx_lastname_age", columnList = "lastName, age")) public class User { private String lastName; private Integer age; } - Составные индексы также могут обслуживать запросы только на сортировку (
ORDER BY) или группировку (GROUP BY), если порядок столбцов в этих операциях совпадает с порядком в индексе.
Ответ 18+ 🔞
А, составной индекс, говоришь? Ну это ж, блядь, классика жанра! Ситуация, когда ты пытаешься одним махом, как говорится, накрыть сразу несколько своих косяков в запросах. Представь, что у тебя в таблице users лежат фамилии и возраст. И ты постоянно ищешь то по фамилии, то по фамилии и возрасту вместе.
Так вот, составной индекс — это как взять и склеить эти два столбца в одну умную папку, которую база данных будет листать в разы быстрее. Создаётся он элементарно:
CREATE INDEX idx_users_lastname_age ON users(last_name, age);
Вот теперь самое интересное, ёпта! Работает эта штука по правилу левого префикса. Это как с дверью, у которой три замка подряд. Если у тебя ключ только от первого — откроешь. От первого и второго — откроешь. От всех трёх — вообще красота. А вот если ключ только от второго или третьего — нихуя не откроешь, будешь ломиться вхолостую.
То есть наш индекс (last_name, age) поможет, если в запросе есть:
- Только
last_name(первый замок). - И
last_name, иageвместе (оба замка).
Работает:
-- Ищет по первому столбцу индекса — летит!
SELECT * FROM users WHERE last_name = 'Ivanov';
-- Ищет по обоим — вообще пуля!
SELECT * FROM users WHERE last_name = 'Ivanov' AND age = 30;
А вот это — полный пиздец и сканирование всей таблицы:
-- Возраст — это второй столбец в индексе, без фамилии он нихуя не стоит!
SELECT * FROM users WHERE age = 30;
База посмотрит на этот запрос, на индекс и скажет: «Мужик, ты чё, блядь? Я по этой твоей папке могу быстро найти всех Ивановых, а потом среди них — тридцатилетних. А как я тебе быстро найду всех тридцатилетних, не зная фамилии? Придётся всю таблицу, сука, перерыть!». И перероет. А ты потом будешь охуевать, почему запрос тормозит.
Короче, главный лайфхак: когда создаёшь такой индекс, первым делом суй туда столбец с самой высокой селективностью — тот, в котором больше всего уникальных значений. Или тот, по которому чаще всего ищешь строгое равенство (=).
В Hibernate, если ты вдруг с ним работаешь, это можно сделать прямо в ентити, не вылезая в чистый SQL. Аннотацией прилепить:
@Entity
@Table(indexes = @Index(name = "idx_lastname_age", columnList = "lastName, age"))
public class User {
private String lastName;
private Integer age;
}
И ещё прикол: если у тебя в запросе есть ORDER BY last_name, age, то такой индекс может отдать данные уже в отсортированном виде, даже не напрягаясь. Красота же!
Так что думай головой, когда их создаёшь, а не тыкай столбцы как попало. А то накропаешь индексов овердохуища, а толку — ноль ебать.