一个基本的实现
考虑到您描述的数据和访问模式,我将设置一个student-data
带有分区键的表,允许我按学生查询,以及一个排序键,允许我根据我的实体进一步缩小结果范围想要访问。这样做的一种方法是为学生使用某种标识符,例如studentID
,然后为排序键使用更通用的标识符entityID
,或者简单地说SK
。
在应用程序层,我会将每个项目分类到一个可能的实体 ( profile
, grades
, address
) 下,并将与该实体相关的数据存储在该项目上我需要的任意数量的属性中。
该数据如何查找名为 john smith 的学生的示例:
{ studentId: "john", entityId: "profile", firstName: "john", lastName: "smith" }
{ studentId: "john", entityId: "grades", math2045: 96.52, eng1021:89.93 }
{ studentId: "john", entityId: "address", state: "CA", city: "fresno" }
使用此架构,您的所有访问模式都可用:
“给我约翰学生的数学成绩”
PartitionKey = "john", SortKey = "grades"
如果您将地址存储在学生profile
实体中,则可以一次性完成“给我学生约翰的个人资料和地址” (应尽可能避免多次查询)
PartitionKey = "john", SortKey = "profile"
考虑
请记住,在设计表格时,您需要考虑读取/写入数据的频率。这是一个非常基本的设计,可能需要进行调整以确保您不会为未来的重大成本或性能问题做好准备。
此实现展示的基本思想是,非规范化数据(在这种情况下,跨您已建立的不同实体)可能是利用 DynamoDB 速度的一种非常有效的方式,同时也为您提供了多种有效访问数据的方法.
问题与局限
具体到您的应用程序,有一个突出的潜在问题,即grades
项目开始膨胀到无法管理并且读取/写入/更新变得昂贵的程度似乎非常可行。随着您开始存储越来越多的学生,并且每个学生都学习越来越多的课程,您的grades
实体将随着他们而扩展。假设普通学生参加 35-40 节课并为每节课打分,如果不需要,您不想管理一个项目的 35-40 个属性。每次询问学生的成绩时,您也可能不希望返回每个成绩。也许您开始在每个grade
实体上存储更多数据,例如:
{ math1024Grade: 100, math1024Instructor: "Dr. Jane Doe", math1024Credits: 4 }
现在对于每个类,您至少要存储 2 个额外的属性。那个有35-40属性的项目刚刚跃升到105-120属性。
除了性能和成本问题之外,您的访问模式可能会开始演变并变得更加苛刻。您可能只想要学生专业的成绩,或者当前不可用的特定类型的课程,如人文、科学等。你永远只能从每个学生那里得到每一个成绩。您可以将 aFilterExpression
应用于您的请求并删除一些不需要的项目,但您仍然需要为您阅读的所有数据付费。
使用当前的解决方案,我们在性能、灵活性、可维护性和成本方面的优化方面留下了很多东西。
优化
解决查询缺乏灵活性和grades
实体可能膨胀的一种方法是使用composite sort key
. 使用复合排序键可以帮助您进一步分解实体,使它们更易于更新,并在查询时为您提供更大的灵活性。此外,您最终会得到更小且更易于管理的物品,尽管您存储的物品数量会增加,但您将节省成本和性能。通过更优化的查询,您将只获得所需的数据,因此您无需为丢弃的数据支付额外的读取单元。单个查询请求可以返回的数据量也是有限的,因此您可以减少往返次数。
该复合排序键可能看起来像这样,因为grades
:
{ studentId: "john", entityId: "grades#MATH", math2045: 96.52, math3082:91.34 }
{ studentId: "john", entityId: "grades#ENG", eng1021:89.93, eng2203:93.03 }
现在,您可以说“给我所有约翰的数学课程成绩”,同时仍然能够获得所有成绩(通过begins_with
在查询时使用排序键上的操作)。
如果您认为要开始在grades
实体下存储更多课程信息,您可以在复合排序键后加上课程名称、编号、标识符等。现在您可以获得所有学生的成绩,所有学生的成绩在其中一个科目,以及有关学生在该科目内成绩的所有数据,例如其讲师、学分、所学年份、学期、开始日期等。
这些优化都是可能的解决方案,但可能不适合您的应用程序,因此请再次记住这一点。
资源
这里有一些资源可以帮助您提出自己的解决方案,或者调整我在上面提供的解决方案以更好地适合您的方法。
AWS re:Invent 2019:使用 Amazon DynamoDB 进行数据建模 (CMY304)
AWS re:Invent 2018:Amazon DynamoDB 深入探讨:DynamoDB 的高级设计模式 (DAT401)
使用排序键组织数据的最佳实践
DynamoDB 的 NoSQL 设计
请记住这一点,尤其是当您考虑对高流量应用程序的成本/性能影响时:
有效设计和使用分区键的最佳实践