Индексы (Indexes)
Какие типы индексов есть в AngaraBase, когда их использовать и как они взаимодействуют с MVCC.
AngaraTree — index engine
AngaraTree — индексный движок AngaraBase. Индексы хранятся внутри .adb-файла базы данных (страницы с page_type = 1), вместе с heap-страницами; отдельного файла индексов нет. См. Хранение данных.
B+tree (default)
Основной тип индекса. Подходит для equality- и range-запросов; ключи хранятся в детерминированном порядке.
-- Создание B+tree индекса (эквивалентные формы):
CREATE INDEX idx_name ON orders (customer_id);
CREATE INDEX idx_name ON orders USING btree (customer_id);
B+tree индекс ускоряет:
- Точные совпадения:
WHERE customer_id = 42 - Диапазоны:
WHERE created_at >= '2026-01-01' AND created_at < '2026-02-01' - Сортировку:
ORDER BY customer_id
BRIN (Block Range Index)
Компактный индекс для данных с естественным порядком (append-only, time-series). BRIN хранит min/max значения для диапазонов heap-страниц, что позволяет пропускать целые блоки при сканировании.
CREATE INDEX idx_ts ON events USING brin (created_at);
Поддерживаемые типы ключей:
| Тип | Алиасы |
|---|---|
INTEGER | int, int4 |
BIGINT | int8 |
DATE | — |
TIMESTAMP | — |
TIMESTAMPTZ | — |
Как BRIN работает: индекс выступает как accelerator path — сначала отсекаются блоки, не содержащие нужных значений, затем выполняется heap fetch с MVCC predicate recheck. BRIN не гарантирует точность — он только сужает область поиска.
Метрика эффективности: angara_brin_range_efficiency показывает долю блоков, пропущенных благодаря BRIN.
Чем ближе к 1.0, тем эффективнее индекс (данные хорошо кластеризованы).
Hash / Bloom
Зарезервированы как optional/future index types. На данный момент не реализованы.
Индексы и MVCC
Индекс хранит ссылки TID (page_id, slot_id) на строки в heap. Видимость строки определяется не
индексом, а MVCC-слоем при чтении heap-страницы:
- Запрос обращается к индексу → получает набор TID.
- По каждому TID читается heap-страница.
- MVCC-слой проверяет видимость версии строки для текущей транзакции.
Следствие: индекс может содержать ссылки на невидимые (устаревшие) версии строк. Это нормально — такие записи фильтруются при heap fetch.
IndexStore — персистентные вторичные индексы
AngaraBase поддерживает персистентные вторичные индексы для RowStore таблиц через IndexStore.
Как работает
CREATE INDEXстроит индекс через полный скан таблицы (build_from_rows) и сохраняет результат.- DML (INSERT/DELETE) автоматически обновляет все индексы таблицы — fail-closed: если обновление индекса не удалось, heap mutation откатывается.
- Оптимизатор использует индекс для
WHERE col = valueзапросов (O(log N) вместо O(N) seq_scan).
Ресурсные ограничения
Обслуживание индекса ограничено по времени (fail-closed): если вставка/удаление
в индекс не укладывается в бюджет, DML откатывается, а счётчик
angarabase_index_reject_total инкрементируется.
| Ограничение | Конфиг | По умолчанию | При нарушении |
|---|---|---|---|
| Время обслуживания индекса | storage.index_maintenance_budget_ms (env ANGARABASE_INDEX_MAINTENANCE_BUDGET_MS) | 5000 мс (0 — отключить) | MaintenanceBudgetExceeded → DML abort |
Реджект angarabase_index_reject_total покрывает также внутренние пределы
(KeyTooLarge, PageLimitExceeded); отдельного публичного кноба на число
страниц нет.
Наблюдаемость
| Метрика | Описание |
|---|---|
angarabase_index_inserts_total | Всего вставок в индекс |
angarabase_index_deletes_total | Всего удалений из индекса |
angarabase_index_reject_total | Отклонённые DML из-за ошибок индекса |
angarabase_index_maintenance_duration_ms | Гистограмма времени обслуживания индекса |
Текущие ограничения
| Ограничение | Статус |
|---|---|
| Только single-column индексы | Текущая версия (v0 bound) |
| Нет partial indexes | Не поддержано (v4 scope) |
| Нет expression indexes | Не поддержано (v4 scope) |
| Нет covering indexes | Не поддержано (v4 scope) |
| Online index build (без блокировки DML) | Не поддержано (H1-v0.7.x) |
| WAL-first для index mutations | In-memory index: восстанавливается через build_from_rows при recovery. Disk-backed WAL-first — в roadmap дальнейших релизов. |
Попытка создать неподдерживаемый индекс возвращает SQLSTATE 0A000 (feature_not_supported).
Когда создавать индексы
Рекомендуется:
- На колонках, часто используемых в
WHERE,JOIN ON,ORDER BY. - BRIN — на time-series колонках таблиц с
append_only = true, где данные вставляются в порядке возрастания ключа.
Не рекомендуется:
- На таблицах с малым количеством строк (full scan будет быстрее).
- На колонках с очень низкой селективностью (например,
boolean-флаги). - Создание множества индексов на одной таблице замедляет
INSERT/UPDATE/DELETE.
Используйте EXPLAIN ANALYZE для проверки, использует ли оптимизатор индекс. Подробнее — Обработка
запросов.
Перестроение индекса
Полное перестроение индекса выполняется командой REINDEX:
REINDEX INDEX idx_name;
REINDEX CONCURRENTLY INDEX idx_name; -- без долгой блокировки DML
Полезно после частичного восстановления при старте (метрика
angarabase_index_restore_capped_total ≠ 0 означает, что индекс поднят не
полностью) или для возврата места после массовых удалений (merge страниц в v0
нет — место освобождает REINDEX).
Связанные разделы
Концепции (что почитать дальше)
- Обработка запросов — как оптимизатор выбирает и комбинирует индексы.
- Хранение данных — как страницы B+tree ложатся в tablespace.
- Транзакции и MVCC — почему обновление индексов под нагрузкой требует MVCC-видимости.
How-to (что сделать)
- DDL: CREATE/DROP INDEX — синтаксис создания и удаления индексов.
- Диагностика — как через
EXPLAIN ANALYZEиsys.*понять, используется ли индекс.
Справочник
- Типы данных — какие типы поддерживаются как ключи индексов.
- Системные представления
sys.*—sys.indexes,sys.column_statsдля анализа покрытия.