> Как индекс определяет, какую запись отдать при поиске по таблице (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Wildberries
Стек: Go
> Пример ответа
Короткий ответ
Индекс - это отдельная структура данных (обычно B-tree или hash), которая хранит отсортированные копии значений ключевых колонок и ссылки на строки таблицы. При поиске СУБД сначала обходит индекс, находит нужные ключи, затем по ссылкам (rowid, primary key или heap pointer) читает сами строки. Индекс не хранит данные таблицы - только ключи и указатели, поэтому поиск по индексу имеет сложность O(log n) вместо полного сканирования O(n).
Подробное объяснение
Индекс работает как справочник: вместо перебора всех строк таблицы, СУБД ищет значение в отсортированной структуре. Основные механизмы:
-
Структура индекса - в PostgreSQL и MySQL (InnoDB) это B-tree. Листовые узлы содержат пары "ключ → ссылка на строку". Ссылка - это физический адрес (ctid в PostgreSQL) или первичный ключ (в InnoDB secondary index).
-
Процесс поиска:
- СУБД получает запрос с условием
WHERE col = value - Планировщик выбирает индекс, если он есть на
col - Происходит обход B-tree от корня к листу, сравнивая ключи
- На листе находится запись с ключом и ссылкой на строку
- По ссылке выполняется чтение строки из таблицы (это называется lookup или table access by rowid)
- СУБД получает запрос с условием
-
Типы индексов:
- Clustered (в InnoDB primary key) - строки физически хранятся в порядке индекса, лист содержит всю строку, lookup не нужен
- Non-clustered (secondary) - лист содержит только ключ и ссылку, требуется дополнительное чтение строки
-
Покрывающий индекс - если все нужные колонки есть в самом индексе, СУБД не обращается к таблице вообще (index-only scan). Это ключевой приём оптимизации.
-
Селективность - индекс эффективен, когда условие отбирает малый процент строк. Если индекс возвращает >10-15% строк, планировщик может выбрать seq scan, потому что lookup по каждой строке дороже полного сканирования.
-
Стоимость - индекс ускоряет чтение, но замедляет запись: каждая INSERT/UPDATE/DELETE должна обновлять все индексы на таблице. Это trade-off, который нужно учитывать.
На практике
В Go-бэкенде с PostgreSQL или MySQL:
- Индексы создаются через миграции:
CREATE INDEX idx_users_email ON users(email) - ORM (GORM, sqlx) не создают индексы автоматически - это ответственность разработчика
- Для поиска по
WHERE user_id = ?в таблице orders нужен индекс наuser_id- иначе будет seq scan при росте таблицы - Составные индексы: порядок колонок критичен.
(user_id, created_at)эффективен дляWHERE user_id = ? ORDER BY created_at, но бесполезен дляWHERE created_at = ? - В Go важно проверять планы запросов через
EXPLAIN ANALYZE- это стандартная практика при оптимизации
Пример кода
GO// Миграция для создания индекса// 001_create_indexes.up.sqlCREATE INDEX idx_orders_user_id ON orders(user_id);CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);// Проверка плана запроса// psql: EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 42;// Результат: Index Scan using idx_orders_user_id on orders// В Go-коде - обычный запрос, индекс работает на уровне БДrows, err := db.Query(ctx, "SELECT * FROM orders WHERE user_id = $1", userID)
Как отвечать на собеседовании
Начни с краткого определения: индекс - это отсортированная структура, которая позволяет находить строки без полного сканирования. Затем опиши механизм: обход B-tree, поиск ключа, чтение строки по ссылке. Упомяни разницу между clustered и non-clustered индексами, а также index-only scan. Обязательно скажи про trade-off: ускорение чтения ценой замедления записи. Если спросят про Go - подчеркни, что индексы управляются на уровне БД, а в коде важно писать запросы, которые могут использовать индексы (не оборачивать колонки в функции, не использовать LIKE '%...').
Что проверяет интервьюер
- Понимание внутреннего устройства индексов, а не только синтаксиса
CREATE INDEX - Знание trade-off между скоростью чтения и записи
- Умение объяснить, почему индекс не всегда эффективен (селективность, покрытие)
- Понимание разницы между типами индексов и структур данных
- Практический опыт: когда создавать индекс, как проверять план запроса
Типичные ошибки
- Утверждение, что индекс хранит копию всей таблицы - это неверно, он хранит только ключи и ссылки
- Игнорирование стоимости записи: "индексы всегда ускоряют" - нет, они замедляют DML
- Непонимание разницы между clustered и non-clustered индексами
- Создание индексов на каждую колонку без анализа реальных запросов
- Использование
SELECT *с индексом - это часто убивает index-only scan, потому что нужны все колонки - Утверждение, что индекс гарантирует порядок выборки - порядок гарантирован только при
ORDER BYв запросе, иначе СУБД может вернуть строки в любом порядке
> Похожие задачи по Go
Почему в некоторых случаях используется сбалансированное дерево вместо хэш-таблицы
Как работает полнотекстовый индекс GIN в PostgreSQL
Сколько букв нужно для поиска в индексе
Как избежать гонок и рейсов в базе данных
> Похожие задачи по backend
Почему в некоторых случаях используется сбалансированное дерево вместо хэш-таблицы
Как работает полнотекстовый индекс GIN в PostgreSQL
Сколько букв нужно для поиска в индексе
Как избежать гонок и рейсов в базе данных
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью