Недавно я прочитал этот раздел документации ElasticSearch (точнее руководство). В нем говорится, что вы должны попытаться использовать нереляционную базу данных предполагаемым способом, а это означает, что вам следует избегать объединений между разными таблицами, потому что они не предназначены для их хорошей обработки. Это также напоминает мне раздел в документации DynamoDB, в котором говорится, что для большинства хорошо спроектированных бэкэндов DynamoDB требуется только одна таблица.
Возьмем в качестве примера базу данных рецептов, в которой в каждом рецепте используются несколько ингредиентов. Каждый ингредиент можно использовать во многих рецептах.
Вариант 1. Для меня очевидный способ смоделировать это в AppSync и DynamoDB - это начать с таблицы ingredients
, в которой есть один элемент для каждого ингредиента, в котором хранятся все данные ингредиентов, с ingredient id
в качестве ключа раздела. Затем у меня есть еще одна таблица recipes
с ключом разделения recipe id
и поле ingredients
, в котором хранятся все ingredient id
в массиве. В AppSync я мог затем запросить рецепт, выполнив запрос GetItem с помощью recipe id
, а затем разрешив поле ingredients
с помощью BatchGetItem в таблице ingredients
. Скажем, рецепт содержит в среднем 10 ингредиентов, так что это будет означать, что к таблицам DynamoDB будет отправлено 11 запросов GetItem.
Вариант 2: Я бы счел эту операцию «подобной соединению», которая, по-видимому, не является идеальным способом использования нереляционных баз данных. Итак, в качестве альтернативы я мог бы сделать следующее: Сделать «избыточные копии» всех данных ингредиентов в таблице recipes
и не только сохранить там ingredient id
, но также и все другие данные из таблицы ingredients
. Это может значительно увеличить использование дискового пространства, но очевидно, что дисковое пространство дешевое, и повышение производительности за счет выполнения только 1 запроса GetItem (вместо 11) может того стоить. Как описано далее в руководстве по ElasticSearch, это также потребует некоторой дополнительной работы для обеспечения параллелизма при обновлении данных ингредиентов. Поэтому мне, вероятно, придется использовать поток DynamoDB для обновления всех данных в таблице recipes
, когда обновляется ингредиент. Это потребует дорогостоящего сканирования, чтобы найти все рецепты с использованием обновленного ингредиента, и BatchWrite для обновления всех этих элементов. (Однако обновление ингредиентов может быть редким, поэтому увеличение производительности чтения может того стоить.)
Мне было бы интересно услышать ваше мнение по этому поводу:
- Какой вариант вы бы выбрали и почему?
- Второй «более нереляционный способ» сделать это кажется болезненным, и я обеспокоен тем, что с появлением большего количества уровней / отношений (например, если пользователи могут создавать меню из рецептов), возникающая сложность может быстро выйти из-под контроля, когда я для многократного сохранения «дублирующих копий» одних и тех же данных. Я мало что знаю о реляционных базах данных, но там эти вещи кажутся намного проще, когда все данные имеют свое уникальное местоположение и все (я думаю, это то, что означает «нормализация»).
- Действительно ли
getRecipe
вариант 1 в 11 раз дороже (с точки зрения производительности и стоимости), чем вариант 2? Или я что-то неправильно понял? - Будет ли вариант 1 более дешевой операцией в реляционной базе данных (например, MySQL), чем в DynamoDB? Несмотря на то, что это соединение, если я правильно понимаю, это всего лишь 11 («предполагаемый способ NoSQL») операций GetItem. Может ли это быть быстрее, чем 1 запрос SQL?
- Если у меня очень реляционная структура данных, может ли нереляционная база данных, такая как DynamoDB, быть плохим выбором? Или AppSync / GraphQL - это способ сделать его жизнеспособным выбором (разрешив вариант 1, который действительно легко создать)? Я читал некоторые мнения, которые постоянно работают над отсутствием возможности соединения при запросе к базам данных NoSQL, и необходимость делать это на стороне приложения является основной причиной, по которой это не подходит. Но AppSync может помочь решить эту проблему. В других мнениях (включая документы DynamoDB) проблемы производительности упоминаются как основная причина, по которой вы всегда должны запрашивать только одну таблицу.