Ответ
Поля в составном индексе следует перечислять в порядке убывания селективности (от наиболее уникальных к наименее уникальным) и с учетом типичных запросов.
Почему?
- Селективность: Наиболее селективное поле (например,
user_id) быстро отфильтровывает большую часть данных, уменьшая объем для последующей фильтрации. - Порядок в WHERE: Индекс эффективно используется, если запрос фильтрует по префиксу индекса. Индекс
(A, B, C)подходит дляWHERE A=1 AND B=2, но не дляWHERE B=2.
Пример (PostgreSQL):
-- Плохо: status имеет низкую селективность (всего 3-4 значения)
CREATE INDEX idx_bad ON orders (status, user_id, created_at);
-- Хорошо: user_id высокоселективен, часто используется в фильтрах
CREATE INDEX idx_good ON orders (user_id, status, created_at);
-- Запрос, который эффективно использует idx_good:
SELECT * FROM orders
WHERE user_id = 12345 AND status = 'shipped'
ORDER BY created_at DESC;
-- Индекс обеспечит быструю фильтрацию по user_id, затем по status и сортировку по created_at.
Дополнительно: Также важно учитывать поля, используемые в ORDER BY или JOIN. Индекс может покрывать запрос (covering index), если включает все выбираемые поля.
Ответ 18+ 🔞
Э, слушай, давай разжую тебе эту тему про индексы, а то некоторые их создают, как бог на душу положит. Ебать мои старые костыли, видел я такие творения — поле status с тремя значениями ставят первым, а потом удивляются, почему запрос тормозит, как полупидор в гору.
Вот смотри, главный принцип — поля в индекс пихай по убыванию селективности. Это как если бы ты искал друга Васю в толпе: сначала смотришь на лицо (уникально), а потом уже на цвет его штанов (не очень). Так и тут. Самый уникальный признак — вперёд. Поле user_id, которое у каждого своё, отсеет овердохуища строк сразу, а уже потом по status будем фильтровать оставшуюся мелочь.
И ещё одна хитрая жопа — порядок в WHERE. Индекс, чувак, он работает как префикс. Если у тебя индекс (A, B, C), то запрос с WHERE A=1 AND B=2 — красота, всё летает. А вот если ты начнёшь с WHERE B=2, то тут уже пизда рулю, индекс можно выкинуть, будет полный скам. База пойдёт читать всю таблицу, а это, считай, волнение ебать на ровном месте.
Смотри на живом примере, чтобы не быть мартышлюшкой:
-- Плохой индекс. Ставим status первым. Он что, имеет 3 значения? Ну и хуй с горы.
-- По нему почти всё равно что всю таблицу сканировать.
CREATE INDEX idx_bad ON orders (status, user_id, created_at);
-- А вот хороший, адекватный индекс. user_id — уникальный чувак, его в топ.
CREATE INDEX idx_good ON orders (user_id, status, created_at);
-- Запрос, который будет просто летать с idx_good:
SELECT * FROM orders
WHERE user_id = 12345 AND status = 'shipped'
ORDER BY created_at DESC;
Видишь магию? Индекс сразу отхватывает все заказы юзера (их немного), потом внутри них тыкает в статус 'shipped', и да — данные уже отсортированы по created_at, так что сортировка не нужна вообще. Красота, ёпта.
И последний лайфхак: если хочешь вообще ни хуя себе скорость, сделай covering index. Просто включи в индекс все поля, которые выбираешь в SELECT. Тогда база данных даже в таблицу лезть не будет, всё возьмёт из индекса. Это как если бы ты пришёл в бар, а тебе сразу готовый коктейль в руки суют, без очереди. Удовольствие, блядь.
Короче, думай головой, когда индексы строишь, а не тыкай поля наугад. Иначе будет тебе хиросима, а не производительность.