Поиск данных и индексы
4. Поиск данных и индексы
4.1. Стратегии чтения
Query
Самая важная операция в DynamoDB. 90% ваших запросов должны быть Query.
- Аналогия: Вы знаете, что книги Толстого стоят на полке "Т" (Partition Key). Вы подходите к этой конкретной полке и берете все книги, написанные после 1860 года (Sort Key). Вы не бегаете по всей библиотеке, вы работаете в рамках одной секции (партиции).
- Что делает: Достает группу элементов, у которых одинаковый Partition Key.
- Суперсила: Вы можете фильтровать по Sort Key (диапазоны).
- Стоимость: Платите только за тот объем книг, который сняли с полки. Это очень эффективно.
from boto3.dynamodb.conditions import Key
# Дай мне все заказы Алисы (Полка), начиная с 2024 года (Фильтр по порядку)
response = table.query(
KeyConditionExpression=Key('PK').eq('USER#alice') & Key('SK').begins_with('ORDER#2024')
)
items = response['Items']
Scan
Операция, которую нужно избегать в повседневной работе.
- Аналогия: Вам нужно найти книгу, в которой на 5-й странице есть слово "синхрофазотрон". Вы не знаете ни автора, ни названия. Вам приходится брать каждую книгу в библиотеке, открывать её и читать. Библиотека парализована, библиотекари в мыле, вы платите огромные деньги за аренду зала.
- Что делает: Читает ВСЮ таблицу. Строка за строкой. С первой по последнюю.
- Фильтрация: Вы можете передать
FilterExpression, но DynamoDB применит фильтр ПОСЛЕ того, как прочитает данные с диска и снимет с вас деньги. - Стоимость: Огромная. Вы платите за прочтение всей таблицы, даже если найдете 0 книг.
- Когда использовать: Только для миграций или редких админских скриптов. Никогда на горячем пути пользователя.
4.2. Вторичные индексы
Ограничения Primary Key
Итак, вы построили идеальное хранилище (таблицу Users), где все лежит по user_id (PK). "Дай мне юзера user_123" - мгновенный ответ.
Но тут приходит менеджер и просит:
- "А найди мне пользователя по
email?" - "А покажи мне всех пользователей из
city='Pavlodar'?"
В SQL вы бы сказали "без проблем" и добавили CREATE INDEX ix_users_email ON users (email).
В DynamoDB ваш единственный способ запроса - это Query по ключу. Если у вас нет ключа для email, вы не можете сделать по нему запрос (кроме Scan, который мы не рассматриваем, так как это медленно и дорого).
Вторичный индекс (Secondary Index) - это копия вашей таблицы (или ее части), но с другим Primary Key. Это ваш "альтернативный паттерн доступа". Это как карточный каталог в библиотеке.
Global Secondary Index (GSI)
GSI - это индекс, у которого Partition Key (а опционально и Sort Key) отличается от основного ключа таблицы.
Пример: Таблица Users.
- Primary Key:
user_id(PK) - Бизнес-задача: "Найти пользователя по email".
- Решение: Мы создаем GSI (назовем его
EmailIndex) с ключом:- GSI PK:
email
- GSI PK:
Архитектура и ограничения
- Это копия: GSI - это, по сути, новая таблица, которой DynamoDB управляет за вас. Когда вы пишете в основную таблицу, DynamoDB асинхронно реплицирует эти данные в GSI.
- Асинхронность: Репликация занимает время (обычно < 1 секунды). Это значит, что GSI всегда Eventually Consistent. Вы не можете делать
Strongly Consistent Readиз GSI. (Про виды консистености будет рассказано ниже.) - Проекция (Projections): GSI не обязан хранить весь элемент. Вы можете выбрать:
KEYS_ONLY: GSI хранит только ключи (основной таблицы и GSI). Дешево по хранению, но чтобы получитьuser_name, вам придется сделать 2-й запрос к основной таблице.INCLUDE: Хранить ключи + некоторые атрибуты (указанные вами).ALL: Хранить полную копию элемента. Дорого по хранению, но быстро по чтению (не нужен 2-й запрос).
- Свой RCU/WCU: У GSI есть свой собственный бюджет RCU и WCU. Вы платите за хранение GSI и за его RCU/WCU отдельно.
Стоимость и производительность
- Запись: Каждая
PutItemв основную таблицу теперь потребляет WCU основной таблицы И WCU индекса (если атрибуты GSI изменились). GSI удваивает (или утраивает, ...) стоимость записи. - Чтение:
Query(IndexName='EmailIndex', KeyConditionExpression=...)потребляет RCU индекса, а не таблицы.
Редкий индекс (Sparse Index)
Это мощный паттерн. GSI копирует элемент только если в элементе присутствует атрибут Partition Key этого GSI.
- Пример: У вас есть
Orders. Вы хотите GSI для "открытых" заказов. - Решение: Вы создаете GSI с Partition Key
open_order_status. Вы записываете этот атрибутopen_order_status = 'OPEN'только еслиstatus = 'OPEN'. - Теперь ваш GSI хранит только 1% данных (открытые заказы). Он маленький, дешевый и быстрый.
Но вы должны помнить, что Primary Key (Partition Key + Sort Key) должен быть уникальным и в индексе тоже. Поэтому, когда у вас Partition Key одинаковый, вы должны так подобрать Sort Key, чтобы их комбинация была уникальной в каждом элементе.
Local Secondary Index (LSI)
LSI - это более редкий и специфичный зверь.
Сценарий: Таблица GameScores.
- Primary Key:
user_id(PK),game_id(SK). - Это позволяет мне делать
Query(user_id='alice')и получать все игры, в которые играла Алиса, отсортированные поgame_id. - Проблема: А что, если я хочу получить все игры Алисы, но отсортированные по
score(счету), чтобы построить ее личный топ?
Локальный вторичный индекс (LSI) - это индекс, у которого Partition Key тот же самый, а Sort Key - другой.
Таблица GameScores:
- Primary Key:
user_id(PK),game_id(SK) - LSI (назовем
ScoreIndex):- LSI PK:
user_id(тот же!) - LSI SK:
score(другой!)
- LSI PK:
Свойства LSI
- Общая партиция: Данные LSI хранятся на той же партиции, что и основные данные.
- Общий RCU/WCU: LSI не имеет своего бюджета. Он ест RCU/WCU из бюджета основной таблицы.
- Создание: LSI нельзя добавить к существующей таблице. Его можно создать только в момент создания таблицы. (GSI можно добавлять и удалять на лету).
- Лимит 10 ГБ: Суммарный размер всех элементов для одного PK (включая все его LSI) не может превышать 10 ГБ.
Когда LSI предпочтительнее GSI?
- Строгая консистентность: Так как LSI живет на той же партиции, вы можете делать
Strongly Consistent Readиз LSI. - Транзакции: LSI можно использовать в
TransactWriteItems. (Про транзакции будет рассказано ниже.) - Экономия: Если у вас и так read-heavy таблица, LSI "бесплатен" (он просто делит RCU/WCU).
Вывод:
- Нужен другой Partition Key? -> GSI.
- Нужна другая сортировка для того же Partition Key? -> LSI.
Query, Scan и вторичные индексы
Вопросов: 7
4.3. Практика
Реализация поиска данных и вторичных индексов для конкурента Twitter
Вы продолжаете работу как CTO стартапа-конкурента Twitter. Вместе с Назаром разберите стратегии чтения данных в DynamoDB: Query vs Scan, проектирование Global Secondary Index для поиска твитов по хэштегам, Local Secondary Index для сортировки ленты, и оптимизация паттернов доступа для высоконагруженного приложения.
Назар - ваш персональный ИИ-наставник. Он поможет закрепить материал через практику и ответит на ваши вопросы.
💡 Все обсуждения с ИИ могут быть прочитаны администратором для улучшения качества обучения.