Открыть сервис

Локальный вторичный индекс

Локальный вторичный индекс — это структура данных в системах управления базами данных (СУБД) и распределённых хранилищах, которая создаётся и поддерживается на одном узле (сервере, шарде, партиции) без координации с другими узлами. В отличие от глобального вторичного индекса, который охватывает все данные кластера, локальный индекс работает только с данными, физически расположенными на данном узле, и не требует распределённых транзакций или протоколов согласования для своего обновления.

История и предпосылки появления

Концепция локальных индексов возникла как эволюция традиционных индексов реляционных баз данных (например, B-деревьев в Oracle или SQL Server) в контексте распределённых систем. В классических монолитных СУБД все индексы были локальными по умолчанию, так как данные хранились на одном сервере. С переходом к шардированию (сегментированию) и распределённым архитектурам (NoSQL-системы, NewSQL) возникла проблема: глобальные индексы требуют синхронизации между узлами, что снижает производительность записи и увеличивает задержки.

Первые реализации локальных вторичных индексов появились в системах, ориентированных на высокую доступность и горизонтальное масштабирование, таких как Apache Cassandra (около 2010 года) и MongoDB (с версии 2.0). В этих системах локальные индексы стали компромиссом между скоростью записи и возможностью фильтрации данных по неключевым полям.

Устройство и принцип работы

Архитектура

Локальный вторичный индекс хранится на том же узле (шарде), что и соответствующие строки данных. Каждый узел владеет определённым диапазоном первичных ключей (или хешей), и для этих данных строится собственный индекс по указанному вторичному полю. Индекс может быть реализован в виде B-дерева, хеш-таблицы или LSM-дерева (Log-Structured Merge-tree) — в зависимости от СУБД.

Процесс создания и обновления

  1. Создание: администратор базы данных выполняет команду CREATE INDEX с указанием ключа индекса (например, CREATE INDEX idx_status ON orders(status) USING LOCAL). СУБД сканирует данные на каждом узле и строит индекс локально.
  2. Обновление: при вставке, обновлении или удалении строки на узле индекс на этом же узле обновляется атомарно в рамках той же транзакции (если СУБД поддерживает транзакции на уровне узла). Никаких сообщений другим узлам не отправляется.
  3. Поиск: запрос с условием по индексированному полю отправляется на все узлы (или на один, если известно распределение данных). Каждый узел использует свой локальный индекс для быстрого поиска строк в своей части данных. Затем результаты агрегируются на координаторе запроса.

Отличия от глобального индекса

ХарактеристикаЛокальный вторичный индексГлобальный вторичный индекс
Область действияОдин узел (шард, партиция)Все узлы кластера
СинхронизацияНе требуетсяТребуется распределённая координация
Производительность записиВысокая (без задержек на сеть)Средняя или низкая (из-за 2PC или Paxos/Raft)
Производительность чтенияНизкая при широком поиске (сканирование всех узлов)Высокая (прямой доступ к одному узлу)
Сложность реализацииНизкаяВысокая
Типичные СУБДCassandra, MongoDB, DynamoDB (локальные вторичные индексы), CockroachDBGoogle Spanner, Amazon DynamoDB (глобальные вторичные индексы), TiDB

Классификация локальных вторичных индексов

По типу структуры данных

По способу хранения

Применение в различных СУБД

Apache Cassandra

В Cassandra локальный вторичный индекс (Local Secondary Index, LSI) создаётся на одном узле для данных, хранящихся в определённом диапазоне партиций. Индекс реализован на основе хранилища SSTable и использует LSM-дерево. Запрос с использованием LSI (SELECT * FROM orders WHERE status = 'shipped') отправляется на все узлы, которые параллельно сканируют свои индексы. Это подходит для небольших наборов данных (до нескольких тысяч записей на партицию), но неэффективно для больших объёмов из-за полного сканирования кластера.

MongoDB

MongoDB поддерживает локальные индексы на уровне коллекции. Индекс создаётся для всех документов в коллекции на одном шарде (если используется шардирование). При запросе с использованием локального индекса MongoDB отправляет запрос на все шарды (broadcast), каждый шард использует свой индекс, и результаты объединяются. Это стандартное поведение для вторичных индексов в MongoDB, если не включён глобальный индекс (доступен в MongoDB Atlas).

Amazon DynamoDB

DynamoDB предоставляет два типа вторичных индексов: локальные (Local Secondary Index, LSI) и глобальные (Global Secondary Index, GSI). LSI создаётся для одной партиции (partition key) и может иметь другой ключ сортировки (sort key). Он хранится на том же узле, что и основная таблица, и обновляется синхронно при записи. LSI позволяет выполнять запросы с условиями по вторичному ключу в пределах одной партиции без полного сканирования.

CockroachDB

CockroachDB — NewSQL-система, которая по умолчанию использует глобальные индексы, но поддерживает локальные индексы (через ключевое слово STORING или INCLUDE). Локальный индекс в CockroachDB — это индекс, который хранится в той же партиции (range), что и данные. Он не требует распределённых транзакций для обновления, что повышает производительность записи, но ограничивает область поиска одной партицией.

Преимущества и недостатки

Преимущества

Недостатки

Сравнение с альтернативами

Глобальный вторичный индекс (GSI)

GSI обеспечивает прямой доступ к данным по вторичному ключу без сканирования всех узлов, но требует распределённой координации при записи. В системах с высокой нагрузкой на запись (более 10 000 записей в секунду) GSI может стать узким местом из-за блокировок и сетевых задержек. Локальный индекс предпочтительнее для сценариев, где запись доминирует над чтением, а запросы по вторичному полю редки или ограничены одной партицией.

Полное сканирование (full scan)

Без индекса запрос по неключевому полю приводит к полному сканированию всех данных на всех узлах. Локальный индекс ускоряет этот процесс, так как каждый узел использует индекс для фильтрации своих данных, но всё равно требует отправки запроса на все узлы. Полное сканирование без индекса может быть в 10–100 раз медленнее.

Примеры использования

Критика и ограничения

Локальные вторичные индексы критикуются за неэффективность при запросах, которые требуют поиска по всему кластеру. В распределённых системах с большим числом узлов (более 10) broadcast-запросы с использованием локальных индексов могут приводить к значительному увеличению времени ответа и нагрузки на сеть. В таких случаях рекомендуется использовать глобальные индексы или денормализацию данных (материализованные представления).

Кроме того, локальные индексы не поддерживают уникальность на уровне кластера — уникальность может быть гарантирована только в пределах одного узла. Это ограничение делает их непригодными для полей, которые должны быть уникальными глобально (например, email пользователя).

Источники

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →