🧭 学习目标:结合电商商品与订单系统,理解 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 库存 | 关系模型或支持原子条件更新的存储 | 库存记录 | 避免超卖 |
| 订单历史 | 订单聚合或关系模型 | 订单与订单项快照 | 保存交易发生时的事实 |
| 商家订单列表 | 派生查询模型 | 权威订单 | 按商家、状态和时间高效筛选 |
| 推荐关系 | 图模型 | 订单、验证关系与运营配置 | 支持多种关系与变深遍历 |
五、关键操作的最终防线
推荐系统允许短暂展示已经下架的商品,但交易链路必须分层校验:
- 推荐阶段尽量过滤下架商品。
- 商品详情读取权威商品状态。
- 加入购物车时再次检查;购物车只保存购买意向。
- 提交订单时重新校验商品状态、品牌状态、SKU、实时价格和库存。
- 创建订单时通过条件更新预占或扣减库存。
商品详情和购物车是体验防线;提交订单与库存操作才是正确性防线。
六、复习清单
- 能区分嵌入与引用
- 能解释规范化与反规范化的权衡
- 能识别权威数据和派生数据
- 能解释丢失更新及基本解决方式
- 能根据访问模式选择关系、文档和图模型
- 能解释声明式查询的优势
- 能解释 MapReduce 为什么不应执行外部副作用
- 能判断图规则的业务语义是否足以支持推导
七、一句话复盘
不要先问“应该使用哪一种数据库”,而要先问“数据如何被读取和修改、哪些事实必须准确、哪份数据是权威来源,以及其他表示能否由它重建”。