Дизайн хранилища данных - Как моделировать эффективные объединения - PullRequest
4 голосов
/ 21 октября 2011

У меня вопрос по дизайну базы данных Google Cloud Datastore.Позвольте мне объяснить это на примере:

У меня есть сущности вида " Article " со следующими свойствами:

  • title
  • userId
  • ....
  • sumOfScore

SumOfScore должен быть суммой всех связанных объектов "Score", которыеимеют такие свойства, как:

  • articleId
  • userId
  • оценка

в псевдо-SQL:
sumOfScore = выбрать сумму (балл) из баллов, где Score.articleId = article.id

Я вижу две возможности для создания этого (с помощью API хранилища данных Google):

1.) Нет свойства sumOfScore для статей;но запрос всегда:

Это означает: каждый раз, когда статья читается, мне нужно сделать запрос для этой конкретной статьи для расчета суммыOfScore.Представьте себе список из 100 статей, который показывается пользователю.Это потребует дополнительных 100 запросов к базе данных, просто чтобы показать счет для каждой статьи.

Тем не менее: Это был бы мой предпочтительный способ при использовании Relational-DB.Нет избыточности и хорошая нормализация.А с SQL вы можете использовать только одно соединение-выборку, чтобы перехватить все данные.Но для Cloud Datastore это не кажется правильным.

2.) Рассчитывайте sumOfScore при каждом изменении сущностей Score:

Это означает: всякий раз, когда Score-Entity являетсяПосле добавления, удаления или изменения соответствующая статья обновляет свойство sumOfScore.

Преимущество: при чтении статей дополнительные запросы не требуются.SumOfScore является избыточным для самой сущности.

Недостаток: каждый раз, когда изменяется оценка, существует один дополнительный запрос и дополнительная запись (обновление сущности Article).И sumOfScore может не соответствовать фактическим сущностям Score (например, значение изменяется через консоль DB)

Что думают более опытные люди?Есть ли лучшая практика для такого сценария?Что делают реализацию JPA или JDO под капотом?

Большое спасибо

Мос

Ответы [ 2 ]

2 голосов
/ 21 октября 2011

Первое, что я рекомендую вам посмотреть в статье GAE о счетчиках шардинга .

Это статья из передового опыта GAE, касающаяся того, как вам следует обращаться со счетчиками / суммами.Это может быть немного сложно, потому что каждый раз, когда вы обновляете элемент, вы должны использовать логику, чтобы случайным образом выбрать счетчик;и когда вы получаете свой счет, вы фактически выбираете группу сущностей и суммируете их.Я прошел этот путь, но не предоставлю здесь код того, как я это сделал, потому что я еще не тестировал его в бою.Но ваш код может стать неаккуратным в спешке, если вы просто скопируете / вставите образец кода шардинга повсеместно, поэтому создайте абстрактный или типизированный счетчик для повторного использования логики шардинга, если вы решите пойти по этому пути.* Другой альтернативой будет использование нечеткого счета.Этот метод использует memcache и предлагает лучшую производительность за счет точности.

См. Раздел здесь, помеченный как «Переходные и часто обновляемые данные»

И последний вариант;это просто использовать SQL. Он экспериментальный и горячий из духовки (по сравнению с использованием на GAE), но, возможно, стоит посмотреть.

1 голос
/ 21 октября 2011

Есть третья возможность, которая не идет на компромисс.

Вы зарабатываете Балл ребенка Артикул и сохраняете sumOfScore в Артикул . В целях сортировки это поле пригодится. Поскольку эти два класса принадлежат одной и той же группе сущностей, вы можете создать Счет и обновить Статья в транзакции. Вы можете даже перепроверить, запрашивая у всех Оценка , чей родитель является данным Статья .

Проблема этого подхода в том, что вы можете обновлять сущность только 5 раз в секунду. Если вы думаете, что у вас будет намного больше активности, чем эта (помните, что это всего лишь ограничение на одну сущность, а не на более раннюю таблицу), вам следует обратиться к учебнику по sharded counter или просмотреть Google io's видео , объясняющее это ..

редактирование:

Вот отличная дискуссия на эту же тему: Как Google Moderator избегает конфликтов?

...