Go: Индексы

11 вопросов

1 Зачем нужны индексы в БД?

Индексы ускоряют поиск, сортировку и JOIN за счет структуры данных (обычно B-tree), позволяя не сканировать всю таблицу. Ускоряют WHERE, ORDER BY, GROUP BY. Минусы: место на диске, замедление INSERT/UPDATE/DELETE (обновление индекса). В Go приложение лишь выполняет запросы; индексы создают миграциями под реальные паттерны доступа.

Открыть отдельно →
2 Как устроен B-tree индекс?

B-tree - сбалансированное дерево: данные в листьях, ключи в узлах для навигации. Поиск, вставка, удаление - O(log N). Листья отсортированы - удобно для диапазонов (BETWEEN, >, ORDER BY). В Postgres и MySQL индексы по умолчанию - B-tree. Подходит для сравнений и сортировки по одному или нескольким столбцам.

Открыть отдельно →
3 Составной индекс. Порядок столбцов и использование в запросах.

Индекс по нескольким столбцам (a, b, c) может использоваться для запросов по (a), (a, b), (a, b, c), но не эффективно для (b) или (c) отдельно. Порядок важен: сначала столбцы с равенством (=), затем диапазон/сортировка. Пример: WHERE status = 'active' ORDER BY created_at - индекс (status, created_at). В Go запросы формулируют так, чтобы префикс индекса совпадал.

CREATE INDEX idx ON orders (status, created_at);
Открыть отдельно →
4 Частичный (partial) и покрывающий (covering) индекс.

Partial index строится по подмножеству строк: CREATE INDEX ... WHERE status = 'active'. Меньше размер, быстрее обновление. Covering index содержит все столбцы запроса (Index-Only Scan): в Postgres через INCLUDE. Запрос выполняется без обращения к таблице. В Go выгодно выбирать только нужные столбцы, чтобы использовать covering index.

CREATE INDEX idx ON orders (user_id) INCLUDE (total, status);
Открыть отдельно →
5 Индекс по выражению (expression index).

Индекс строится по выражению (функция от столбца), а не по столбцу напрямую. Пример: WHERE lower(email) = 'a@b.com' - индекс CREATE INDEX ON users (lower(email)). В Postgres поддерживается; в MySQL - через виртуальный столбец и индекс по нему. Запрос должен использовать то же выражение, что и индекс.

CREATE INDEX idx_lower_email ON users (lower(email));
Открыть отдельно →
6 Когда используют hash-индекс?

Hash-индекс подходит только для точного совпадения (=), не для диапазонов и ORDER BY. В Postgres hash редко выигрывает у B-tree; в MySQL MEMORY-таблицы используют hash по умолчанию. Для точечных запросов по ключу иногда выгоден. В приложении на Go выбор типа индекса делают в миграциях под паттерны запросов.

CREATE INDEX idx_hash ON t USING HASH (key_col);
Открыть отдельно →
7 Индексы GIN и GiST в Postgres. Когда какой?

GIN (Generalized Inverted Index) - для полнотекста, массивов, JSONB (операторы @>, ?, содержания). Построен по элементам; эффективен когда один документ дает много ключей. GiST - для геоданных, диапазонов, полнотекста; может давать false positives, нужна проверка по таблице. В Go запросы к JSONB и полнотексту автоматически используют подходящий индекс при правильном определении.

CREATE INDEX ON events USING GIN (data jsonb_path_ops);
Открыть отдельно →
8 Когда индексы вредят производительности?

Много индексов на часто обновляемой таблице - каждый INSERT/UPDATE/DELETE обновляет все затронутые индексы. Лишние индексы занимают место и замедляют запись. Индекс не используется, если условие не совпадает (другое выражение, тип), или оптимизатор выбирает full scan (малая таблица, большая доля строк). Удаляют неиспользуемые индексы по pg_stat_user_indexes.

Открыть отдельно →
9 Типы сканирования: index scan, seq scan, index-only.

Seq Scan - последовательное чтение всей таблицы. Index Scan - обход индекса, по ссылкам чтение строк таблицы. Index-Only Scan - данные берутся только из индекса (covering). Bitmap Index Scan - по индексу строят битовую карту строк, затем читают таблицу по порядку. В EXPLAIN видно тип; в Go оптимизируют запросы и индексы под план.

Открыть отдельно →
10 Как читать EXPLAIN при анализе индексов?

EXPLAIN (ANALYZE) показывает план: тип узла (Seq Scan, Index Scan, Index Only Scan), оценка и фактические rows, cost, время. Смотреть: нет ли Seq Scan по большой таблице без необходимости; используется ли ожидаемый индекс; высокие rows или cost. В Go выполняют EXPLAIN вручную или логируют планы при отладке; индексы добавляют миграциями по результатам анализа.

EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM users WHERE email = $1;
Открыть отдельно →
11 Стратегия создания индексов в продакшене.

Создавать индексы под реальные запросы после анализа (EXPLAIN, pg_stat_statements). На проде - CREATE INDEX CONCURRENTLY, чтобы не блокировать запись. Не создавать индексы "на всякий случай"; мониторить использование (pg_stat_user_indexes.idx_scan). В Go миграции с CONCURRENTLY выполняют отдельно от транзакции; при сбое проверять pg_index на invalid и пересоздавать.

CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_name ON table (col);
Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.