数据建模
选让访问模式快、未来变更便宜的存储模型和 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 重要。