Что такое составной индекс в базах данных и как его создать?

Ответ

Да, в большинстве реляционных баз данных можно создавать составные (composite) индексы, которые включают в себя несколько колонок. Это позволяет значительно ускорить выполнение запросов, фильтрующих данные сразу по нескольким полям.

Зачем это нужно? Составной индекс эффективен для запросов вида WHERE column1 = 'value1' AND column2 = 'value2'. Без него базе данных пришлось бы сначала фильтровать по одному индексу, а затем сканировать полученные результаты по второму условию.

Пример на чистом SQL:

CREATE INDEX idx_name_email ON users (name, email);

Пример в Go с использованием GORM: В GORM составные индексы удобно определять с помощью тегов структуры. Важно дать одинаковое имя индексу в тегах у всех полей, которые должны в него войти.

type User struct {
    ID    uint
    Name  string `gorm:"index:idx_name_email"`
    Email string `gorm:"index:idx_name_email"`
    Age   int
}

Ключевые моменты:

  • Порядок полей в индексе критически важен. Запрос WHERE Name = ? сможет использовать индекс (Name, Email), а запрос WHERE Email = ? — как правило, нет. Запрос должен использовать поля в том порядке, в котором они определены в индексе (левый префикс).
  • Компромисс производительности. Составные индексы ускоряют чтение (SELECT), но могут незначительно замедлять операции записи (INSERT, UPDATE), так как базе данных нужно обновлять и индексную структуру.

Ответ 18+ 🔞

А, ну ты про индексы составные, да? Вот эта магия, когда база данных не тупит, как пень, а летает, как ракета, когда ты ищешь по нескольким полям сразу. Да, блядь, это реально работает, не выдумка.

Смотри, представь себе таблицу users. Ты ищешь Васю Пупкина с почтой vasya@mail.ru. Без индекса база будет чесать репу и перебирать всё подряд, как дурак. А если создать индекс сразу по двум полям — (name, email) — то она сразу, блядь, как хитрая жопа, прыгнет прямо на нужную запись. Всё потому, что она заранее всё отсортировала и знает, где что лежит.

Как это в коде выглядит, ёпта? Вот, смотри, на чистом SQL это делается просто:

CREATE INDEX idx_name_email ON users (name, email);

А в Go, с этим нашим любимым GORM'ом, ещё проще. Прямо в структуре прописываешь. Главное — дать одинаковое имя индексу у всех полей, которые должны в него войти, а то он не поймёт, что они связаны, и наделает кучу отдельных индексов, дурак.

type User struct {
    ID    uint
    Name  string `gorm:"index:idx_name_email"` // Вот тут имя одно
    Email string `gorm:"index:idx_name_email"` // И тут то же самое, блядь!
    Age   int
}

Но, слушай сюда, самое важное, что все хуёво понимают: Порядок полей в индексе — это пиздец как важно! Это не просто список, это, блядь, иерархия! Индекс (name, email) — это как телефонный справочник: сначала по фамилии, а потом уже по имени внутри фамилии.

  • Запрос WHERE name = 'Вася' — охуенно, использует индекс.
  • Запрос WHERE name = 'Вася' AND email = '...' — идеально, использует индекс на полную катушку.
  • А вот запрос WHERE email = '...' — нихуя! Он этот индекс, скорее всего, проигнорирует, потому что искать почту без имени — это как искать иголку в стоге сена, начиная с середины стога. Бесполезно, блядь.

И да, компромисс, куда же без него. Такие индексы — они как спортивная машина: читает (SELECT) — овердохуища быстро, но каждая запись (INSERT, UPDATE) становится чуть дороже, потому что движку базы приходится не только данные писать, но и эту свою хитрую индексную структуру обновлять. Но обычно оно того стоит, если запросы частые.

В общем, думай головой, где у тебя узкие места, и применяй эту штуку точечно. Не навешивай индексы на всё подряд, а то получишь обратный эффект, и всё встанет колом.