DynamoDB表设计咨询:获取用户未作答的已发布问题
DynamoDB表设计方案:适配用户未作答题目查询与结果数据高增长场景
针对你的需求,结合DynamoDB的特性,以下是几种高效的表设计方案,重点解决QuestionResult数据快速增长下的查询性能问题:
方案一:单表设计(DynamoDB最佳实践)
DynamoDB单表设计通过合理的主键设计,避免跨表关联,提升整体读写效率,尤其适合多实体关联查询场景。
表结构定义
- 分区键(PK):采用
实体类型#ID格式,区分不同实体:- Question实体:
QUESTION#<QuestionID> - User实体:
USER#<UserID> - QuestionResult实体:
USER_RESULT#<UserID>
- Question实体:
- 排序键(SK):用于实体内部的排序和区分:
- Question实体:
ORDER#<Order>(按题目顺序排序) - User实体:
USER_DATA(固定值,标识用户数据) - QuestionResult实体:
QUESTION#<QuestionID>(关联对应的题目ID)
- Question实体:
- 全局二级索引(GSI1):
- 分区键:
IS_PUBLISHED#<IsPublished>(如IS_PUBLISHED#true) - 排序键:
ORDER#<Order> - 投影属性:
PK(即QUESTION#<QuestionID>)
- 分区键:
查询流程
- 获取用户已作答题目ID:
执行Query操作,指定PK = 'USER_RESULT#<目标UserID>',SK前缀匹配QUESTION#,返回所有已作答的QuestionID集合(从PK中提取数字部分)。 - 获取未作答的已发布题目:
查询GSI1,指定PK = 'IS_PUBLISHED#true',按SK升序排序,分页获取题目。在客户端过滤掉已在步骤1集合中的QuestionID,直到凑够10条。
优化点
- 每次查询GSI1时多取5-10条数据(比如取15条),减少分页次数,提升过滤效率。
- 利用DynamoDB的投影表达式,仅返回QuestionID和Order,减少数据传输量。
方案二:多表设计+针对性GSI
如果习惯分表管理实体,可采用以下设计,兼顾数据隔离和查询效率:
各表结构
Questions表
- 分区键(PK):
QuestionID(int) - 属性:
Order(int)、IsPublished(bool)、Data(JSON) - GSI1:
- 分区键:
IsPublished(bool) - 排序键:
Order(int) - 投影属性:
QuestionID
- 分区键:
- 分区键(PK):
Users表
- 分区键(PK):
UserID(int) - 属性:
Data(JSON)、LastAccessedOrder(int,可选,用于优化查询)
- 分区键(PK):
QuestionResults表
- 分区键(PK):
UserID(int) - 排序键(SK):
QuestionID(int) - 属性:
Result(JSON)
- 分区键(PK):
查询流程
- 获取用户已作答题目ID:
执行Query操作,指定PK = <目标UserID>,返回所有SK(即QuestionID)组成的集合。 - 高效获取未作答题目:
- 如果用户表有
LastAccessedOrder属性,先查询GSI1,指定IsPublished = true且Order > <LastAccessedOrder>,按Order升序取15条,过滤掉已作答的题目,凑够10条后更新LastAccessedOrder为这批题目的最大Order。 - 若上述结果不足10条,再查询
Order <= <LastAccessedOrder>的已发布题目,过滤未作答的补充。
- 如果用户表有
适配高增长场景的优势
- QuestionResults表采用
UserID作为PK、QuestionID作为SK,写入请求会均匀分布到不同分区,避免热点问题,支撑高并发写入。 - GSI1的查询是高效的范围扫描,配合
LastAccessedOrder可大幅减少需要过滤的数据量,尤其适合用户持续获取新题的场景。
关键注意事项
- 避免全表扫描:所有查询必须基于主键或GSI,绝对禁止对QuestionResults表做全表扫描来过滤用户已答题。
- 数据去重:写入QuestionResult时,使用条件表达式
attribute_not_exists(QuestionID),确保每个用户对同一题目仅存一条结果。 - 批量操作:如果需要批量检查题目是否已作答,可使用
BatchGetItem操作,减少单次请求次数。
内容的提问来源于stack exchange,提问作者Mykyta Karpyshyn
相关产品推荐
相关产品推荐

