> Какой индекс предложить для запроса с условиями по курсу студента и полу и почему (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Wildberries

Стек: Go

> Пример ответа

Короткий ответ

Предложу композитный индекс (course_id, gender) или (gender, course_id) - выбор зависит от селективности и частоты запросов. Для типичного сценария "все студенты конкретного курса с фильтром по полу" оптимален (course_id, gender), так как первое условие максимально сужает выборку, а второе добирает остаток. Если пол фильтруется чаще как самостоятельное условие - лучше начать с (gender, course_id). В PostgreSQL это B-tree индекс, в MySQL - тоже, если движок InnoDB.

Подробное объяснение

Индекс выбирается исходя из того, какие условия в WHERE наиболее селективны и как часто встречаются в запросах. Для запроса вида WHERE course_id = ? AND gender = ? композитный индекс позволяет:

  • использовать оба условия для доступа к строкам, а не фильтровать после чтения;
  • избежать сортировки, если есть ORDER BY по тем же колонкам.

Порядок колонок в композитном индексе критичен: B-tree позволяет эффективно использовать префикс индекса. Если индекс (course_id, gender), то он работает для запросов с course_id отдельно и с course_id + gender вместе. Индекс (gender, course_id) - для gender отдельно и для пары. Выбор зависит от того, какие запросы чаще: "все студенты курса" или "все студенты по полу".

Если селективность course_id высокая (например, 1000 курсов на 100k студентов), то (course_id, gender) даст меньше чтений. Если пол почти равномерен (50/50), то gender первым колонкой бесполезен для сужения - он лишь добавит overhead на запись. В этом случае лучше (course_id, gender).

Дополнительно стоит учесть:

  • если запросы всегда содержат оба условия, порядок не критичен для производительности чтения, но влияет на возможность покрытия других запросов;
  • если есть ORDER BY course_id или GROUP BY course_id, индекс (course_id, gender) поможет избежать сортировки;
  • для MySQL с InnoDB вторичный индекс автоматически включает primary key, поэтому лишние колонки в индексе увеличивают размер.

На практике

Для Go-бэкенда с PostgreSQL типичный сценарий - репозиторий с методами вида GetStudentsByCourseAndGender. Здесь важно:

  • проверить план запроса через EXPLAIN ANALYZE - убедиться, что используется Index Scan, а не Seq Scan;
  • если таблица большая, рассмотреть partial index, например, только для активных студентов, если пол фильтруется редко;
  • не создавать отдельные индексы на course_id и gender по отдельности, если есть композитный - они будут дублировать префикс.

В MySQL с InnoDB стоит помнить про ограничение на длину ключа (3072 байта для DYNAMIC row format) - для course_id и gender это не проблема, но если добавить student_name varchar(255) - уже может быть.

Пример кода

SQL
-- PostgreSQL
CREATE INDEX idx_course_gender ON students (course_id, gender);
-- проверка плана
EXPLAIN ANALYZE
SELECT * FROM students
WHERE course_id = 42 AND gender = 'female';
GO
// Go: метод репозитория
func (r *StudentRepo) GetByCourseAndGender(ctx context.Context, courseID int, gender string) ([]Student, error) {
rows, err := r.db.QueryContext(ctx, `
SELECT id, name, course_id, gender
FROM students
WHERE course_id = $1 AND gender = $2
`, courseID, gender)
// обработка ошибок и сканирование
}

Как отвечать на собеседовании

Начни с уточнения: какой СУБД пользуетесь, какой объём таблицы, какие ещё запросы есть к этой таблице. Затем предложи композитный индекс и объясни порядок колонок через селективность. Упомяни, что проверил бы через EXPLAIN. Покажи понимание trade-off: индекс ускоряет чтение, но замедляет запись и увеличивает размер. Если спросят про покрывающий индекс - скажи, что можно добавить student_name в INCLUDE (PostgreSQL) или в конец индекса (MySQL), если запросы часто возвращают только эти колонки.

Что проверяет интервьюер

  • понимание устройства B-tree индекса и понятия селективности;
  • умение обосновать порядок колонок в композитном индексе;
  • знание trade-off между скоростью чтения и стоимостью записи;
  • практический опыт работы с EXPLAIN и настройкой индексов;
  • способность задавать уточняющие вопросы перед ответом.

Типичные ошибки

  • предложить два отдельных индекса на course_id и gender - СУБД сможет использовать только один (в большинстве случаев), второй останется неиспользуемым;
  • поставить gender первым без анализа селективности - если пол распределён примерно поровну, индекс будет почти бесполезен;
  • забыть про влияние на INSERT/UPDATE - каждый индекс увеличивает время записи;
  • не упомянуть проверку через EXPLAIN - это признак отсутствия практики;
  • предложить hash index для диапазонных условий - он не поддерживает сравнения и сортировку.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью