Нужно ли денормализовать таблицу NoSQL (динамодаб), если данные должны запрашиваться независимо? - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть простой API для записи / запроса тренировок и связанных с ними упражнений, созданный с помощью AWS Lambda / API Gateway / Dynamodb. Я ожидаю, что мой вопрос в равной степени применим и к другим базам данных NoSQL, например, MongoDB.

Основная структура проста: между тренировками и упражнениями существует отношение один ко многим, поэтому с точки зрения API /workouts/{id} возвращает тренировку в виде объекта JSON, а /workouts/{id}/exercises возвращает принадлежащие упражнения. на тренировку. Я также хотел бы, чтобы /exercises?exerciseTypeID={exerciseTypeID} вернул все упражнения определенного типа, например, /exercises?exerciseTypeID=4xBT должен вернуть все беговые упражнения.

При структурировании этих данных в DynamodB кажется, что у меня есть два варианта: денормализовать, вложив упражнения в объект тренировки, как показано ниже:

Тренировка (денормализованная):

'id': '8977-9823-QbUU',
    'name': 'Marathon training',
    'date': '22-08-2015',
    'exercises': {
        '1112-0120-XaBt': {
            'name': 'Warmup',
            'exerciseTypeID': '4xBT', # Running
            'distance': '2500', # meters
            'speed': '9', # km/h
            'duration': 1000 # seconds
         },
         '2253-4288-TKhg': {
             'name': '10K practice',
             'exerciseTypeID': '4xBT', # Running
             'distance': '10000',
             'speed': '11',
             'duration': 3272 # seconds
         }

    }

}

Или, в качестве альтернативы, нормализуйте схему и сохраните упражнения в отдельной таблице, связанной с тренировкой с помощью workoutID, как показано ниже:

Тренировки (нормализованные):

{
     'id': '8977-9823-QbUU',
     'name': 'Marathon training',
     'date': '22-08-2015'
}

Упражнения (нормализованные):

{
     'id': '1112-0120-XaBt',
     'workoutID': '8977-9823-QbUU',
     'name': 'Warmup',
     'exerciseTypeID': '4xBT', # Running
     'distance': 2500, # meters
     'speed': 9, # km/h
     'duration': 1000 # seconds
}

{
     'id':  '2253-4288-TKhg',
     'workoutID': '8977-9823-QbUU',
     'name': '10K run',
     'exerciseTypeID': '4xBT', # Running
     'distance': 10000, # meters
     'speed': 11, # km/h
     'duration': 3272 # seconds
}

Первичным запросом к упражнениям было бы получить все упражнения, связанные с конкретной тренировкой. Исходя из этого, я должен денормализовать, сохранив данные упражнения в объекте тренировки, в соответствии с первым примером, так что мне потребуется выполнить только один запрос, чтобы получить тренировку и все связанные упражнения. В качестве альтернативы, если я нормализую, тогда мне нужно будет выполнить 2 запроса в большинстве случаев, когда я получаю тренировку, поскольку необходимость видеть упражнения в тренировке будет интуитивно очень распространенным запросом, то есть нормализованный менее эффективен для этого варианта использования.

Осложнение связано с необходимостью доступа к упражнениям напрямую, независимо от тренировки (возможно, 10% частоты просмотра тренировки и ее упражнений). Похоже, что это будет медленно / дорого в денормализованной схеме. Например, если я хочу понять, как улучшилось мое время выполнения за последние 10 запусков (что я мог бы сделать с помощью вызова API /exercises?exerciseTypeID={exerciseTypeID}), в денормализованном примере мне потребуется выполнить дорогой запрос на все тренировки, чтобы найти Exercises с exerciseTypeID == '4xBT', поскольку я не могу спроецировать свой вложенный workoutTypeID в глобальный вторичный индекс, поскольку он не является атрибутом верхнего уровня.

Я полагаю, что это не может быть особенно экстремальным или необычным сценарием - я упускаю очевидный / простой способ запроса вложенных объектов, который позволил бы мне придерживаться денормализованной схемы? Если нет, то как мне найти компромисс между очень частыми, немного более дорогими запросами к базе данных (2 запроса против 1 запроса) и очень частыми очень эффективными запросами в большинстве случаев и очень медленными в 10% случаев?

...