← Назад к вопросам

Как называется индекс, который относится к нескольким полям?

1.0 Junior🔥 181 комментариев
#Базы данных

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Составной индекс (Compound Index / Composite Index)

Что такое составной индекс?

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

Основная идея заключается в том, что индекс организует данные в упорядоченной структуре (чаще всего B-дерева или его вариаций), где сортировка происходит по первому указанному полю, затем внутри групп с одинаковыми значениями первого поля — по второму, и так далее. Это похоже на сортировку телефонной книги: сначала по фамилии, а внутри однофамильцев — по имени.

Ключевые принципы работы

  1. Порядок полей критически важен. Составной индекс (A, B, C) — это НЕ то же самое, что индексы (A, B), (B, C) или (C, A). Индекс эффективен для запросов, которые используют префикс этого списка:
    *   `(A, B, C)` — отлично.
    *   `(A, B)` — отлично.
    *   `(A)` — отлично.
    *   `(B, C)` или `(C)` — **НЕ будет эффективно использоваться** (в большинстве СУБД, если запрос не начинается с первого поля индекса, происходит полное сканирование индекса или таблицы).

  1. Сортировка (ORDER BY) и группировка (GROUP BY). Составной индекс может исключить дорогостоящую операцию сортировки, если порядок полей в ORDER BY совпадает (или является обратным) с порядком полей в индексе.

Пример в Go с использованием PostgreSQL

Рассмотрим модель пользователя (users) и типичные запросы к ней.

package main

import (
    "gorm.io/gorm"
)

type User struct {
    gorm.Model
    CompanyID uint
    LastName  string
    FirstName string
    Age       int
    IsActive  bool
}

// Допустим, самые частые запросы:
// 1. Найти всех активных пользователей конкретной компании.
// 2. Внутри компании сортировать по фамилии и имени.
// 3. Также часто ищем по компании, фамилии и активности.

// Составной индекс для таких запросов будет выглядеть так:
// CREATE INDEX idx_users_company_ln_fn_active ON users(company_id, last_name, first_name, is_active);

func main() {
    // Пример создания индекса с помощью GORM миграции
    db.AutoMigrate(&User{})
    // GORM позволяет задать составной индекс через тег `compositeIndex` или в миграции
    // Более наглядно — через миграцию:
    db.Exec(`
        CREATE INDEX IF NOT EXISTS idx_users_comp_ln_fn_active
        ON users(company_id, last_name, first_name, is_active)
    `)
}

Как этот индекс ускорит запросы:

// 1. Этот запрос использует префикс индекса (company_id) и одно из последующих полей (is_active).
// СУБД сможет эффективно найти нужную компанию и отфильтровать по активности.
var activeUsers []User
db.Where("company_id = ? AND is_active = ?", 123, true).Find(&activeUsers)

// 2. Этот запрос использует три поля индекса (company_id, last_name, first_name).
// Данные уже отсортированы в индексе, что ускоряет поиск и исключает сортировку.
var sortedUsers []User
db.Where("company_id = ?", 123).
   Order("last_name ASC, first_name ASC").
   Find(&sortedUsers)

// 3. А этот запрос НЕ будет эффективно использовать наш индекс,
// так как он начинается не с company_id, а с last_name.
// Скорее всего, произойдет полное сканирование таблицы (Seq Scan) или другого индекса.
db.Where("last_name = ? AND first_name = ?", "Ivanov", "Petr").Find(&users)

Преимущества и недостатки

Преимущества:

  • Покрывающие индексы (Covering Index): Если индекс содержит ВСЕ поля, запрашиваемые в SELECT, база данных может выполнить запрос, обращаясь только к индексу, без чтения самой таблицы (т.н. index-only scan). Это максимальное ускорение.
  • Оптимизация сложных условий WHERE и ORDER BY.
  • Экономия ресурсов: Один составной индекс часто эффективнее нескольких одиночных, так как уменьшает накладные расходы на обновление и хранение.

Недостатки и особенности:

  • Размер: Составной индекс занимает больше места на диске, чем одиночные.
  • Обновление (INSERT/UPDATE/DELETE): Любое изменение данных в индексированных полях требует пересчета индекса, что замедляет операции записи. Нужно соблюдать баланс между чтением и записью.
  • "Слепые" зоны: Как показано в примере, индекс не помогает запросам, не использующим его префикс.

Вывод

Составной индекс — это не просто "индекс на несколько полей". Это целенаправленная структура, которую проектируют под конкретные шаблоны запросов (query patterns) приложения. Правильное его использование — это искусство баланса, требующее анализа реальной нагрузки (EXPLAIN ANALYZE в SQL). В Go-приложениях, работающих с высокими нагрузками, грамотное проектирование индексов, особенно составных, является одним из ключевых факторов производительности слоя данных.

Как называется индекс, который относится к нескольким полям? | PrepBro