DynamoDB单表设计下扫描过滤查询与分页优化方案咨询
DynamoDB单表设计下全量商品查询与稳定分页实现方案
当前方案的核心缺陷
你当前单表的分区键(PK)格式如下:
P#product1 P#product2 P#product3 W#warehouse1 W#warehouse2 P#product4 ....
目前通过Scan+begins_with(PK, "P#")获取全量商品的方案存在两个无法绕过的问题:
Scan会遍历整张表的所有条目,哪怕加了过滤条件也会先读全量数据再过滤,RCU消耗极高,数据量上涨后性能和成本都会出问题- 分页逻辑不可控:DynamoDB的
Limit参数是在过滤前生效的,设置Limit=10时,单次扫描可能只命中2-3条商品记录,根本拿不到固定大小的分页结果,客户端需要循环拉取、聚合结果才能凑够每页条数,逻辑冗余且容易出问题,完全没法稳定实现87条商品每页10条共9页的预期效果。
推荐方案:常量分区键GSI实现实体聚合
这是DynamoDB单表设计下处理同类型实体全量查询的标准玩法,全程用Query不用Scan,分页逻辑天然符合预期:
实现步骤
- 给主表新增一个全局二级索引(GSI),索引分区键命名为
GSI_PK,排序键命名为GSI_SK - 写入商品类型数据时,给所有商品条目统一设置
GSI_PK = "ENTITY#PRODUCT",GSI_SK = "P#<商品ID>";仓库、其他类型的数据不要给GSI_PK赋值,不会进入这个GSI - 查询全量商品时,直接对这个GSI执行Query操作,指定查询条件
GSI_PK = "ENTITY#PRODUCT"即可,不需要加任何过滤表达式
效果说明
- 资源消耗大幅降低:Query只会扫描GSI里的商品条目,完全不会碰仓库等其他无关数据,读容量消耗只有原Scan方案的几十分之一(按你举的1000条总数据87条商品的例子,消耗直接降到原来的8.7%)
- 分页开箱即用:因为Query返回的所有条目都是商品数据,设置
Limit=10时单次请求就会稳定返回最多10条有效结果,直接用接口返回的LastEvaluatedKey做下一页的游标即可,不需要客户端做额外的结果凑数逻辑,87条商品自然就是9页,完全符合你的预期
扩展能力
如果后续需要按商品创建时间、价格、分类排序,只需要调整商品写入时GSI_SK的格式即可,比如要按创建时间倒序排,就把GSI_SK设为CREATED_AT#<倒序时间戳>#<商品ID>,不需要修改索引结构就能直接支持排序查询。
内容的提问来源于stack exchange,提问作者Duyth
相关产品推荐
相关产品推荐

