Skip to content
返回架构决策

数据建模

选让访问模式快、未来变更便宜的存储模型和 schema。

为什么

数据模型是架构里最难后改的部分——每个查询、索引、迁移都源于它。好 schema 让常见查询走索引、罕见查询可忍;差 schema 让每个查询全表扫、每个新功能迁移噩梦。关系、文档、宽列、图的选择由访问模式(读 vs 写、join vs 聚合)驱动,非潮流。设计时弄对省数月返工;弄错意味着你被卡住,因为迁移活数据存储是最贵的重构。

何时使用

系统设计早期,写第一个查询前。1-2 天。仅当访问模式根本变化时重访。

如何做

1. 列访问模式(查询,非实体):
   - "按 id 取用户"、"按用户列订单按日期排"、"按月聚合消费"
2. 每个标:读重还是写重?需 join?需事务?
3. 选存储:
   - Join + 事务 → 关系(Postgres)
   - 灵活嵌套文档、读重 → 文档(Mongo)
   - 时序、宽行 → 宽列(Cassandra)
   - 关系优先 → 图(Neo4j)
4. 设计 schema 让前 5 访问模式走索引
5. 仅在 join 太慢且读重处反范式
6. 规划迁移:每表需 created_at + 迁移路径

示例

访问模式:
  1. 按 id 取用户(读重、按键)→ Postgres users 表,PK 索引
  2. 按用户列订单按日期排(读重、范围)→ orders(user_id, created_at) 复合索引
  3. 按月聚合消费(读重、扫)→ 预物化 monthly_spend 表,夜刷

Schema:
  users(id PK, email UNIQUE, created_at)
  orders(id PK, user_id FK, amount, created_at) — 索引 (user_id, created_at DESC)
  monthly_spend(month, user_id, total) — PK (month, user_id)

读时无 join(反范式 monthly_spend);迁移走 expand-contract。

常见问题

  • ⚠建实体而非访问模式——得到理论上正确、实践上慢的范式 schema,因为每次读 join 5 表。

最佳实践

  • ✓定 schema 前写 5 个最频查询——任一不能走索引就重设计。
  • ✓用 expand-contract 迁移而非原地 alter——零停机且可逆,对活 DB 重要。

相关资源