В каком порядке нужно перечислять поля при создании составного индекса?

Ответ

Поля в составном индексе следует перечислять в порядке убывания селективности (от наиболее уникальных к наименее уникальным) и с учетом типичных запросов.

Почему?

  • Селективность: Наиболее селективное поле (например, 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. Тогда база данных даже в таблицу лезть не будет, всё возьмёт из индекса. Это как если бы ты пришёл в бар, а тебе сразу готовый коктейль в руки суют, без очереди. Удовольствие, блядь.

Короче, думай головой, когда индексы строишь, а не тыкай поля наугад. Иначе будет тебе хиросима, а не производительность.