DynamoDB单表设计:预订数据选GSI还是手动复制?
手动复制数据的核心原因
在DynamoDB单表设计中选择手动复制预订数据(同时维护PK: SPA#spaID, SK: BOOKING#bookingID和PK: USER#userID, SK: BOOKING#bookingID两条条目),主要是为了获得更高的灵活性和控制力:
- 自定义数据投影与存储优化:手动复制可以给不同分区下的预订条目定制字段。比如给SPA侧的条目只保留
预订时间、房间号、用户ID等SPA运营需要的字段,给用户侧的条目只保留SPA名称、服务类型、订单状态等用户关心的字段,既能减少存储成本,又能让查询返回的数据更精简,提升效率。而GSI的投影策略(全量、键集、指定字段)一旦确定就难以灵活调整。 - 独立的读写资源管控:两个独立的条目可以分别配置读写吞吐量(或按需扩容),避免GSI与主表共享资源带来的瓶颈。比如某热门SPA的预订查询量极大,可以单独给
SPA#xxx分区下的预订条目分配更高的吞吐量,不会影响用户侧订单查询的性能。 - 强事务一致性:通过DynamoDB的
TransactWriteItems事务操作,可以确保两边的预订数据同时写入/更新成功,避免出现一边有数据另一边没有的不一致情况。而GSI的同步是最终一致性,存在短暂延迟,在实时性要求高的场景(比如用户下单后立即查看订单)会出现数据缺失。 - 定制化排序与查询模式:可以给不同分区的排序键设计不同结构,满足特定查询需求。比如SPA侧的SK设为
BOOKING#yyyyMMdd#bookingID,方便按日期范围查询每日预订;用户侧的SK设为BOOKING#PAID#bookingID,方便快速过滤已支付订单。GSI的排序键是固定的,无法针对不同查询场景灵活调整。
GSI容易忽略的限制
你考虑的GSI方案虽然实现简单,但存在不少容易被忽略的限制:
- 最终一致性延迟:GSI的数据同步是异步触发的,主表更新后,GSI可能需要几秒甚至几分钟才能同步完成。在实时性要求高的场景(比如用户刚提交订单就查看自己的订单列表),会出现查询不到数据的情况。
- 投影字段无法动态修改:GSI创建时指定的投影策略(全量、键集、指定字段)无法直接修改,如果后续需要新增投影字段,必须删除现有GSI再重建,这在生产环境中会导致服务中断,因为重建期间GSI无法提供查询服务。
- 吞吐量瓶颈与管控受限:GSI有自己的读写吞吐量,但它的写入操作完全由主表触发,无法单独控制某个GSI的写入速率。当主表写入量突增时,GSI的写入吞吐量可能成为瓶颈,导致数据同步延迟加剧。
- 条目大小限制:GSI的单条条目大小同样不能超过400KB,如果投影了过多字段,很容易触发这个限制,导致写入失败。而手动复制可以灵活控制每个条目的字段数量,避免超出限制。
- 扩展性不足:如果后续需要新增其他查询维度(比如按订单状态查询所有SPA的预订),必须新增GSI;而手动复制可以通过添加新的条目结构,更灵活地支持新的查询需求,无需修改现有索引。
内容的提问来源于stack exchange,提问作者L_Cleo
相关产品推荐
相关产品推荐

