我最近正在阅读this section in the ElasticSearch documentation(或更准确地说是该指南)。它说您应该尝试按预期方式使用非关系数据库,这意味着您应避免在不同表之间进行联接,因为它们并不是为了很好地处理它们而设计的。这也使我想起了DynamoDB文档中的那一部分,该部分指出大多数设计良好的DynamoDB后端仅需要一个表。
让我们以一个食谱数据库为例,其中每个食谱都使用几种成分。每种成分都可以用于许多不同的配方中。
选项1 :对我而言,在AppSync和DynamoDB中进行建模的一种明显方法是,从ingredients
表开始,该表的每个成分都有一个项存储所有成分数据,并以ingredient id
作为分区键。然后,我有了另一个带有分区键recipes
的recipe id
表和一个ingredients
字段,该字段在数组中存储了所有ingredient id
。然后,在AppSync中,我可以通过recipe id
进行GetItem请求,然后使用ingredients
表上的BatchGetItem解析ingredients
字段来查询配方。假设一个食谱平均包含10种成分,那么这意味着将11个GetItem请求发送到DynamoDB表。
选项2:我认为这是一个“类似联接”操作,这显然不是使用非关系数据库的理想方式。因此,或者,我可以执行以下操作:对recipes
表上的所有成分数据进行“冗余复制”,不仅将ingredient id
保存在那里,还保存ingredients
表中的所有其他数据。这可能会大大增加磁盘空间的使用,但是显然磁盘空间很便宜,仅通过执行1个GetItem请求(而不是11个)来提高性能可能是值得的。 As discussed later in the ElasticSearch guide这也将需要一些额外的工作来确保成分数据更新时的并发性。因此,当更新成分时,我可能还必须使用DynamoDB流来更新recipes
表中的所有数据。这将需要进行昂贵的扫描以使用更新的成分来查找所有配方,并需要使用BatchWrite来更新所有这些项目。 (尽管成分更新可能很少见,所以增加读取性能可能是值得的。)
我很想听听您对此的看法:
getRecipe
是否真的比选项2中的昂贵11倍(性能和成本)?还是我误会了什么? 最佳答案
我知道这已经很晚了,但可能会帮助某个人。
从实体关系图开始,因为这将有助于确定您的选择。即使在NoSQL中,也存在标准的关系建模方法。
接下来,定义您的访问模式。遍历所有CRUDL操作,并确保对于每个操作,您都可以访问该操作的特定数据。例如,在选项1中,将配料存储在字段中的阵列中:考虑一种可能需要删除配方中配料的访问模式。为此,您需要知道数组中项目的索引。因此,您必须获取整个数组,找到该项的索引,然后考虑可能的竞争条件,再次发出调用以更新数组。
在可能的情况下,在您的应用程序中执行此操作效率不高。您也可以在解析器中编写代码,但是尝试使用速度模板语言来编写代码并不值得头疼,请相信我。
TL; DR将为整个应用程序的实体关系图建模,并仔细考虑所有访问模式。如果关系是一对多的,则可以对数据进行非规范化,使用复合排序键或使用二级索引。如果是多对多,您将开始进入邻接表和其他高级策略。 Alex DeBrie有一些很棒的资源here和here。
关于elasticsearch - 结合使用AWS Appsync和DynamoDB,您是否应该通过将相关数据的 “redundant copies”存储在同一张表上(去规范化)来建立关系模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52759785/