0Pricing
AWS Solutions Architect · Урок

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

Добавьте GSI и LSI для поддержки альтернативных шаблонов запросов без дублирования таблиц.

«Глобальные и локальные вторичные индексы» — бесплатный урок AWS Solutions Architect на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AWS Solutions Architect, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AWS Solutions Architect содержит 4 уроков всего.

Зачем нужны вторичные индексы

Первичный ключ DynamoDB определяет единственный эффективный путь выполнения запросов к таблице. Если Вам нужно выполнять запросы по другому атрибуту — например, найти все заказы для идентификатора продукта, когда ключом раздела таблицы является CustomerId, — без вторичного индекса пришлось бы выполнять затратную операцию Scan.

Вторичные индексы решают эту проблему, поддерживая отдельную автоматически обновляемую копию данных, организованную вокруг другого ключа. DynamoDB предлагает два типа: Global Secondary Indexes (GSI) и Local Secondary Indexes (LSI), каждый со своими компромиссами.

Основы Global Secondary Index (GSI)

Global Secondary Index позволяет определить полностью отличный от базовой таблицы ключ раздела (и, при необходимости, ключ сортировки). GSI действительно является глобальным: он охватывает все разделы базовой таблицы. Вы можете выполнять запросы к GSI, чтобы находить элементы по любому атрибуту, заданному в качестве ключа раздела GSI.

GSI имеют собственную выделенную пропускную способность (или наследуют режим On-Demand), независимую от базовой таблицы. Для одной таблицы можно создать до 20 GSI, а добавлять или удалять GSI можно в любое время в уже существующей таблице.

# Create a table with a GSI on ProductId
aws dynamodb create-table \
  --table-name Orders \
  --attribute-definitions \
    AttributeName=OrderId,AttributeType=S \
    AttributeName=ProductId,AttributeType=S \
    AttributeName=OrderDate,AttributeType=S \
  --key-schema AttributeName=OrderId,KeyType=HASH \
  --global-secondary-indexes '[
    {
      "IndexName": "ProductId-OrderDate-index",
      "KeySchema": [
        {"AttributeName": "ProductId", "KeyType": "HASH"},
        {"AttributeName": "OrderDate", "KeyType": "RANGE"}
      ],
      "Projection": {"ProjectionType": "ALL"},
      "ProvisionedThroughput": {"ReadCapacityUnits": 10, "WriteCapacityUnits": 5}
    }
  ]' \
  --provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5

Основы Local Secondary Index (LSI)

Local Secondary Index использует тот же ключ раздела, что и базовая таблица, но другой ключ сортировки. LSI называются «локальными», поскольку запросы к ним выполняются только в пределах одного раздела (элементов с одинаковым ключом раздела). Поэтому LSI идеально подходят для запросов заказов конкретного клиента с сортировкой по различным атрибутам.

LSI необходимо определить при создании таблицы — позднее добавить или удалить их нельзя. Каждая таблица может содержать до 5 LSI. LSI используют выделенную пропускную способность базовой таблицы (отдельная пропускная способность не предоставляется) и подпадают под ограничение хранения 10 GB на ключ раздела для совокупности данных базовой таблицы и LSI.

# Create a table with an LSI (at creation time only)
aws dynamodb create-table \
  --table-name Orders \
  --attribute-definitions \
    AttributeName=CustomerId,AttributeType=S \
    AttributeName=OrderDate,AttributeType=S \
    AttributeName=TotalAmount,AttributeType=N \
  --key-schema \
    AttributeName=CustomerId,KeyType=HASH \
    AttributeName=OrderDate,KeyType=RANGE \
  --local-secondary-indexes '[{
    "IndexName": "TotalAmount-index",
    "KeySchema": [
      {"AttributeName": "CustomerId", "KeyType": "HASH"},
      {"AttributeName": "TotalAmount", "KeyType": "RANGE"}
    ],
    "Projection": {"ProjectionType": "ALL"}
  }]' \
  --billing-mode PAY_PER_REQUEST

GSI и LSI: ключевые различия

Для ясности на экзамене приведём сравнение бок о бок:

  • Ключ партиции: у GSI может отличаться от ключа базовой таблицы, а у LSI должен совпадать с ним
  • Ключ сортировки: оба индекса поддерживают ключ сортировки, отличный от ключа базовой таблицы
  • Когда создаётся: GSI можно создать в любое время, а LSI — только при создании таблицы
  • Пропускная способность: у GSI есть собственная пропускная способность, а LSI использует пропускную способность базовой таблицы
  • Согласованность: чтение из GSI поддерживает только итоговую согласованность, а чтение из LSI может быть строго согласованным
  • Ограничения: до 20 GSI и до 5 LSI на таблицу

Типы проекции

При создании индекса Вы выбираете, какие атрибуты будут спроецированы (скопированы) в него:

  • KEYS_ONLY: только первичный ключ базовой таблицы и ключ индекса — самый маленький индекс, для неключевых атрибутов требуются дополнительные вызовы GetItem
  • INCLUDE: ключевые атрибуты и определённый Вами список дополнительных атрибутов — компромисс между размером и способом доступа
  • ALL: в индекс проецируются все атрибуты — наиболее гибкий вариант, но с более высокими затратами на хранение и запись

Выбирайте тип проекции с учётом атрибутов, которые действительно нужны Вашим запросам. Избыточная проекция расходует WCU при каждой записи, а недостаточная вынуждает выполнять дополнительные вызовы GetItem для получения атрибутов, отсутствующих в индексе.

Запросы к GSI

Для запроса к GSI используется тот же API Query, но указывается параметр --index-name. Запрос выполняется по схеме ключей GSI, а не базовой таблицы. Запросы к GSI всегда используют итоговую согласованность: GSI обновляется асинхронно после записи в базовую таблицу, поэтому возможна небольшая задержка.

Если у элемента базовой таблицы отсутствует атрибут ключа партиции GSI, этот элемент вообще не включается в GSI (шаблон разреженного индекса). Это мощный приём для индексации только подмножества элементов, например всех заказов со статусом PENDING, если ключом партиции GSI является Status.

# Query the GSI for all orders for a product in 2026
aws dynamodb query \
  --table-name Orders \
  --index-name ProductId-OrderDate-index \
  --key-condition-expression 'ProductId = :pid AND OrderDate BETWEEN :start AND :end' \
  --expression-attribute-values \
    '{":pid":{"S":"prod-abc"},":start":{"S":"2026-01-01"},":end":{"S":"2026-12-31"}}'

Шаблон разреженного индекса

Разреженный индекс использует тот факт, что DynamoDB проецирует элементы в GSI только при наличии у них значения ключа партиции GSI. Если определить ключ партиции GSI для атрибута, который присутствует только у некоторых элементов, получится индекс только этого подмножества.

Пример: в таблице Orders атрибут PendingShipmentDate есть только у неотправленных заказов. GSI по PendingShipmentDate естественным образом содержит только неотправленные заказы, что делает его очень эффективным способом получить все ожидающие заказы без сканирования всей таблицы.

Шардинг записей с перегрузкой GSI

Перегрузка GSI — это продвинутый приём проектирования одной таблицы, при котором в одной таблице хранятся разные типы сущностей, а для них используется общий атрибут ключа GSI (например, GSI1PK и GSI1SK), заполняемый по разным шаблонам в зависимости от типа элемента. Благодаря этому каждый тип сущности получает собственный эффективный путь выполнения запросов через один GSI.

Пример: для элементов User задайте GSI1PK = 'COUNTRY#US' и GSI1SK = username, а для элементов Order — GSI1PK = 'STATUS#PENDING' и GSI1SK = orderDate. Запрос к GSI с соответствующим префиксом эффективно возвращает нужный тип сущности.

Ограничение скорости и пропускная способность индекса

Ограничение скорости GSI происходит независимо от базовой таблицы. Если выделенных для GSI WCU недостаточно, записи элементов, проецируемых в GSI, будут ограничиваться — даже если у базовой таблицы достаточно пропускной способности. Отслеживайте показатели ConsumedWriteCapacityUnits и ThrottledRequests отдельно для каждого GSI.

Распространённая ошибка — выделить GSI меньшую пропускную способность, чем у базовой таблицы, а затем столкнуться с ограничением скорости при резком увеличении интенсивности записи в GSI. Используйте автоматическое масштабирование для GSI или выберите режим по требованию, чтобы избежать этого.

Когда использовать GSI, LSI или перепроектировать таблицу

Рекомендации для экзамена SAA-C03:

  • Нужно выполнять запросы по совершенно другому атрибуту → GSI
  • Нужно выполнять запросы в той же партиции, но с другой сортировкой, и это известно во время создания → LSI
  • Нужно строго согласованное чтение по альтернативному ключу сортировки → LSI (единственный вариант, поскольку GSI используют итоговую согласованность)
  • Есть десять или более разных шаблонов запросов → рассмотрите проектирование одной таблицы с перегрузкой GSI вместо множества отдельных таблиц
  • Нужно только получать все элементы для анализа → ещё раз оцените, подходит ли DynamoDB в качестве базы данных

Удаление и заполнение GSI

Вы можете удалить GSI в любое время, не затрагивая базовую таблицу. При добавлении нового GSI в существующую таблицу DynamoDB асинхронно заполняет индекс, сканируя базовую таблицу — для больших таблиц это может занять от нескольких минут до нескольких часов. Во время заполнения базовая таблица остаётся полностью доступной для чтения и записи.

Отслеживать ход заполнения можно в консоли или через API DescribeTable, проверяя поле IndexStatus индекса: во время заполнения оно имеет значение CREATING, а после завершения — ACTIVE. Не выполняйте запросы к GSI, пока его статус не станет ACTIVE.

# Check GSI status during backfill
aws dynamodb describe-table \
  --table-name Orders \
  --query 'Table.GlobalSecondaryIndexes[*].{Name:IndexName,Status:IndexStatus}'

Быстрая проверка

Проверьте, насколько Вы поняли концепции AWS Solutions Architect (SAA-C03) из этого урока.

Итоги урока

В этом уроке Вы узнали, что GSI предоставляют альтернативные ключи партиции и могут быть добавлены в любое время, LSI используют общий с базовой таблицей ключ партиции и должны быть определены при создании, а типы проекции определяют, какие атрибуты копируются в индекс. GSI поддерживают шаблоны разреженных индексов и перегрузки для расширения возможностей запросов. Далее мы рассмотрим DynamoDB Streams и глобальные таблицы.

Часто задаваемые вопросы

Урок «Глобальные и локальные вторичные индексы» бесплатный?

Да — полный текст урока «Глобальные и локальные вторичные индексы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AWS Solutions Architect, подпишись на CoddyKit PRO. Курс AWS Solutions Architect содержит 4 уроков всего.

Чему я научусь в уроке «Глобальные и локальные вторичные индексы»?

Добавьте GSI и LSI для поддержки альтернативных шаблонов запросов без дублирования таблиц. Ты практикуешь AWS Solutions Architect с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AWS Solutions Architect?

Предыдущий опыт не требуется. AWS Solutions Architect на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Глобальные и локальные вторичные индексы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AWS Solutions Architect?

Да. Каждый урок AWS Solutions Architect включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Таблицы, элементы и первичные ключи
  2. Выделенная и платная по факту ёмкость
  3. Глобальные и локальные вторичные индексы
  4. Потоки DynamoDB и глобальные таблицы
← Назад к AWS Solutions Architect