> Где хранится индекс и как к нему обращаются (Go)
Уровень: senior · Роль: backend · Категория: Технические вопросы
Компании: Сбер
Стек: Go
> Пример ответа
Короткий ответ
Индекс хранится в отдельной структуре данных на диске и в памяти, отдельно от самих данных таблицы. В PostgreSQL это, как правило, B-tree, в MySQL InnoDB - тоже B-tree, но встроенный в кластеризованный индекс. Доступ к индексу происходит через планировщик запросов: он выбирает индекс на основе статистики, затем движок выполняет поиск по дереву (O(log n)) и получает ссылки на строки (TID или primary key), после чего идёт чтение самих строк из heap-файла. В Go-приложениях доступ к индексу обычно скрыт за драйвером БД, но понимание этого процесса критично для оптимизации запросов.
Подробное объяснение
Индекс - это отдельная структура, физически хранящаяся в собственных файлах (например, _idx в PostgreSQL) или в отдельном tablespace. Он не хранит данные строк, а содержит ключевые значения и указатели на строки.
Классическая схема для B-tree:
- root page - вершина дерева
- internal pages - промежуточные узлы с диапазонами ключей
- leaf pages - конечные узлы, содержащие пары (ключ, TID) или (ключ, первичный ключ)
Доступ к индексу происходит в несколько этапов:
- Парсер и планировщик анализируют запрос, смотрят на статистику (
pg_statistic,information_schema.statistics). - Планировщик оценивает селективность условия
WHEREи решает, использовать ли индекс. - Если индекс выбран, движок выполняет поиск по дереву: спускается от корня к листьям, сравнивая ключи.
- Находит нужные листовые записи, извлекает TID (или PK).
- Выполняет чтение строк из heap-файла по TID (это называется "table access by index rowid").
- Если запрос покрывается индексом (covering index), шаг 5 пропускается - данные берутся прямо из листа.
В MySQL InnoDB ситуация отличается: первичный ключ - это кластеризованный индекс, где листья содержат сами строки. Вторичные индексы хранят PK, а не TID, и для доступа к строке выполняется дополнительный lookup по кластеризованному индексу.
В Go-приложениях доступ к индексу происходит через SQL-запросы, которые отправляются в БД. Сам Go-код не управляет индексами напрямую - это делает СУБД. Однако важно понимать, как индексы влияют на производительность, чтобы писать эффективные запросы и правильно проектировать схему.
На практике
Для backend-разработчика на Go практическое значение сводится к нескольким моментам:
- Индексы создаются через миграции (например,
golang-migrate,goose), а не через ORM-автомиграции в проде. - При написании запросов нужно учитывать, какие индексы существуют: условия
WHERE,ORDER BY,JOINдолжны использовать префиксы составных индексов. - В Go-коде важно использовать prepared statements, чтобы планировщик мог кэшировать план запроса с учётом индексов.
- Для высоконагруженных систем стоит проверять план запроса через
EXPLAIN(в Go это можно делать через отдельный клиент или вручную в psql). - Покрывающие индексы позволяют избежать чтения heap-файла - это особенно полезно для частых OLTP-запросов.
Пример: если есть таблица users(id, email, name) и запрос SELECT name FROM users WHERE email = $1, то индекс на email позволит найти строки, но для получения name потребуется чтение heap. Если создать индекс (email, name), то name будет взят прямо из индекса.
Пример кода
GO// Миграция для создания индекса (пример с golang-migrate)// 000001_create_users_index.up.sqlCREATE INDEX idx_users_email ON users (email);// 000001_create_users_index.down.sqlDROP INDEX idx_users_email;// Go-код: использование prepared statement для доступа к индексуfunc GetUserByEmail(ctx context.Context, db *sql.DB, email string) (*User, error) {// Prepared statement позволяет планировщику переиспользовать планstmt, err := db.PrepareContext(ctx, "SELECT id, name FROM users WHERE email = $1")if err != nil {return nil, err}defer stmt.Close()var u Usererr = stmt.QueryRowContext(ctx, email).Scan(&u.ID, &u.Name)if err != nil {return nil, err}return &u, nil}// Проверка плана запроса (выполняется в psql или через отдельный клиент)// EXPLAIN SELECT id, name FROM users WHERE email = 'test@example.com';
Как отвечать на собеседовании
Начните с краткого определения: индекс - это отдельная структура, ускоряющая поиск. Затем опишите физическое хранение: B-tree, отдельные файлы, листовые страницы с парами (ключ, TID). Обязательно упомяните роль планировщика: он решает, использовать ли индекс, на основе статистики. Расскажите про разницу между кластеризованными и некластеризованными индексами (InnoDB vs PostgreSQL). Если спросят про Go - подчеркните, что доступ к индексу прозрачен для приложения, но важно писать запросы, которые могут использовать индексы, и проверять планы через EXPLAIN.
Хорошо добавить пример из практики: когда индекс не используется (например, из-за функции на колонке или несоответствия типов) и как это диагностировать.
Что проверяет интервьюер
Интервьюер оценивает:
- Понимание внутреннего устройства индексов (B-tree, leaf pages, TID).
- Знание процесса планирования запросов и роли статистики.
- Умение объяснить разницу между кластеризованными и вторичными индексами.
- Практические навыки: когда индекс полезен, а когда вреден (overhead на запись, размер).
- Понимание покрывающих индексов и index-only scans.
- Способность связать теорию с реальной работой backend-разработчика на Go.
Типичные ошибки
- Утверждение, что индекс хранится вместе с данными - это неверно для большинства СУБД (кроме кластеризованных).
- Игнорирование роли планировщика: кандидат думает, что индекс используется всегда.
- Непонимание разницы между TID и первичным ключом в вторичных индексах.
- Утверждение, что индекс ускоряет все запросы - на самом деле он замедляет INSERT/UPDATE/DELETE.
- Путаница между индексом и представлением (view) или материализованным представлением.
- Отсутствие упоминания о необходимости проверки плана через
EXPLAINв реальной работе.
> Похожие задачи по backend
Столкнулись ли вы с проблемами нагруженности таблиц и как их решали
Индексы замедляют или ускоряют чтение и запись в базе данных
Задумываетесь ли вы об оптимизации приложений
Есть ли у вас сильно нагруженные части системы
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью