架构设计

DDIA 第二章:数据模型与查询语言|电商系统实践笔记|2026-09-10

根据访问模式选择文档、关系和图模型,并区分权威数据与派生数据。

🧭 学习目标:结合电商商品与订单系统,理解 DDIA 第二章的数据模型、查询语言、反规范化、派生数据和图模型,并能根据访问模式选择模型。 学习日期:2026-09-10

一、核心结论

数据模型不是单纯的存储格式。它决定了哪些操作自然、哪些操作困难。

  • 文档模型适合整体读取、结构接近树形且字段变化较多的数据。
  • 关系模型适合稳定关联、复杂筛选、约束以及需要事务正确性的业务。
  • 图模型适合关系本身是主要查询对象,并且遍历深度不固定的场景。
  • 反规范化用冗余数据和短暂不一致换取读取效率。
  • 派生模型可以延迟,但必须能够从权威数据重新构建。
  • 展示数据可以短暂陈旧,关键操作必须重新检查权威来源。

二、学习过程中的架构决策

1. 商品与 SKU

商品详情采用适合聚合读取的商品文档,SKU 展示信息可以嵌入;实时库存独立保存。

  • 商品文档服务高频详情读取。
  • SKU 实时库存是独立权威数据,支持单个 SKU 的原子扣减。
  • 页面展示库存不能作为下单依据;提交订单时必须重新校验并原子预占或扣减库存。
  • 展示价格可以是冗余副本,成交价格必须由下单流程确认。

2. 订单商品快照

订单必须保存购买时的信息,避免商品改名、调价或换图后改变历史订单。

订单项同时保存商品 ID、SKU ID,以及购买时的名称、规格、成交价、数量和图片。

  • 商品 ID 和 SKU ID 用于追踪与售后。
  • 名称、规格、成交价和图片是不可变交易快照。
  • 订单记录的是交易发生时的事实,而不是商品当前状态。

3. 品牌数据

最初选择将品牌名称直接嵌入商品,优点是详情读取简单;进一步分析后增加稳定的品牌 ID。

  • 品牌实体是名称和禁售状态的权威来源。
  • 商品中的品牌名称是展示副本,可以异步刷新。
  • 品牌禁售不能依赖批量修改所有商品,应使用稳定的品牌 ID 检查权威禁售状态。
  • 若维护禁售集合,其语义是拒绝列表,而不是白名单。

4. 分类与分页查询

商品保存分类 ID 和展示名称,列表查询使用稳定的分类 ID。

  • 组合索引围绕分类 ID、商品状态、排序字段和商品 ID 建立。
  • 使用游标分页,避免深页偏移扫描。
  • 排序值相同时,以商品 ID 作为稳定的第二排序字段。
  • 分类关系独立保存;进入父分类时,先获得全部后代分类 ID,再查询商品。
  • 分类页面流量很大时,缓存每个分类的后代 ID;分类关系仍是权威来源。

5. 订单聚合与商家查询

订单聚合是权威交易记录;商家订单项集合、财务汇总和搜索索引是派生查询模型。

权威订单包含:

  • 买家与收货地址快照;
  • 订单项快照;
  • 支付状态;
  • 各订单项的发货状态;
  • 售后状态。

派生数据必须遵守:

  • 能够由权威订单重新构建;
  • 使用订单 ID 与订单项 ID 保证重复同步不会生成重复记录;
  • 关键操作不能只信任派生数据;
  • 商家发货前必须重新验证权威订单中的归属、支付、取消、退款和发货状态。

6. 并发修改与丢失更新

如果两个商家同时读取旧订单、分别修改后覆盖整份文档,后写入者可能覆盖先写入者的修改,这称为丢失更新

处理方式:

  • 优先进行针对订单项的原子路径更新;
  • 使用当前状态作为更新条件,防止非法状态跳转;
  • 必要时增加版本号,进行乐观并发控制;
  • 当内部对象具有高度独立的生命周期时,考虑拆分聚合。

7. 灵活商品属性

本次设计选择通用属性表作为权威来源,并为商品详情建立派生文档。

为兼顾审计与范围查询,同时保存:

  • 商家原始输入,例如 16GB;
  • 标准化数值,例如 16;
  • 标准单位,例如 GB;
  • 使用的属性定义或转换规则版本。

这样既能保留原始信息,也能可靠执行“内存至少 16GB”之类的范围筛选。

8. 图模型

商品、用户和分类作为节点;购买、兼容、替代和所属分类作为边。图模型服务兼容关系、替代关系和推荐遍历,不承载订单与实时库存的权威数据。

不同关系具有不同来源:

  • 购买关系来自权威订单;
  • 兼容关系可能来自验证或运营配置;
  • 替代关系可能来自人工配置或算法推导,需要记录可信度;
  • 图中的商品状态和库存只是查询副本。

“C 是 A 的替代品”不能直接推出“C 继承 A 的全部兼容性”。只有当“完全兼容替代”具有严格业务定义,并且接口、协议、尺寸、电压、型号和地区等关键条件一致时,推导才安全。

三、查询语言

声明式查询

声明式查询描述希望得到的结果,让数据库自行选择索引、连接顺序和执行方式。它的优势不只是语法简短,也包括为执行引擎保留优化空间。

MapReduce

Map 和 Reduce 函数应尽量满足:

  • 相同输入产生相同输出;
  • 不直接执行转账、发短信或修改外部系统;
  • 失败重跑不会造成业务损失。

Map 任务可能在外部转账成功、但结果尚未记录时失败;任务重试会导致重复转账。正确做法是先输出结算结果,再由独立结算服务通过唯一支付 ID 和事务账本执行幂等支付。

四、最终电商数据架构

领域 主要模型 权威来源 关键理由
商品详情 派生商品文档 商品与属性数据 整体读取,支持多品类属性
SKU 库存 关系模型或支持原子条件更新的存储 库存记录 避免超卖
订单历史 订单聚合或关系模型 订单与订单项快照 保存交易发生时的事实
商家订单列表 派生查询模型 权威订单 按商家、状态和时间高效筛选
推荐关系 图模型 订单、验证关系与运营配置 支持多种关系与变深遍历

五、关键操作的最终防线

推荐系统允许短暂展示已经下架的商品,但交易链路必须分层校验:

  1. 推荐阶段尽量过滤下架商品。
  2. 商品详情读取权威商品状态。
  3. 加入购物车时再次检查;购物车只保存购买意向。
  4. 提交订单时重新校验商品状态、品牌状态、SKU、实时价格和库存。
  5. 创建订单时通过条件更新预占或扣减库存。

商品详情和购物车是体验防线;提交订单与库存操作才是正确性防线。

六、复习清单

  • 能区分嵌入与引用
  • 能解释规范化与反规范化的权衡
  • 能识别权威数据和派生数据
  • 能解释丢失更新及基本解决方式
  • 能根据访问模式选择关系、文档和图模型
  • 能解释声明式查询的优势
  • 能解释 MapReduce 为什么不应执行外部副作用
  • 能判断图规则的业务语义是否足以支持推导

七、一句话复盘

不要先问“应该使用哪一种数据库”,而要先问“数据如何被读取和修改、哪些事实必须准确、哪份数据是权威来源,以及其他表示能否由它重建”。

相关学习