--- name: data-modeling description: 用于数据库表结构设计(与管理业务术语的 domain-modeling 相对)、ORM 与迁移工具选型及种子数据规划(data modeling)。 --- # 数据建模 设计数据库表结构、确立实体关系、选定迁移机制并规范种子数据。本 skill 关注**持久化层与物理存储设计**;业务层面的概念定义与领域通用语言由 `domain-modeling` skill 负责,两者保持清晰分工。 本 skill 保持**技术栈无关**,不预设具体数据库类型或 ORM 框架,只提供结构化决策维度与权衡考量。 ## 何时主动介入 遇到以下情况时,先按决策清单过一遍再动手改表,而不是写完迁移脚本再回头补考量: - **新建一张承载业务核心数据的表**:主键策略、软删除与否、货币/时间字段的存储方式,先确认清楚再落表,事后改字段类型或主键策略代价远高于一开始就选对。 - **要给生产环境正在使用的表改列名、改类型或删列**:这是不可逆操作,按扩缩三步走(先扩 → 迁移数据 → 后缩)拆分,不接受一次性重命名或直接删列的方案。 - **要给已合并或已在共享环境执行过的迁移文件做修改**:立即制止,改为新增一条修复迁移。 - **种子脚本要写入非本地环境**:先确认写入目标环境,防止测试种子或含隐私数据的种子误刷入生产。 给已有表加可空的新可选字段这类不影响兼容性的小改动,不必每次都重新过一遍完整清单。 ## 决策清单 ### 1. 实体关系(ER)设计 在动工建表前,按照以下维度评估数据模型: - **主键与标识符策略**: - 单调自增整型 ID:存储空间小、索引局部性好;但容易被遍历枚举,暴露业务规模。 - 随机 UUID(如 v4):全局唯一、客户端即可生成;但在聚簇索引中会导致页分裂与写入性能下降。 - 时间有序标识符(如 UUIDv7、NanoID 等):兼顾全局唯一与索引写入性能,适合分布式或高写入场景。 - **关系建模与引用完整性**: - 一对多与多对多:多对多必须设计显式连接表,并确定连接表是否承载业务属性与复合唯一键。 - 外键与级联(Cascade):核心交易数据谨慎使用物理级联删除,优先限制删除(RESTRICT)并在业务层处理;临时或从属记录可配置级联删除。 - 软删除(Soft Delete):采用软删除时,必须评估其对唯一约束(如用户名、邮箱)带来的冲突风险,明确如何设计带软删除标识的联合索引。 - **规范化与反规范化**: - 默认遵循第三范式(3NF)以消除更新异常。 - 高频读、报表或展示场景允许适度冗余字段,但必须明确冗余字段的一致性更新策略(事务内同步更新 vs 异步最终一致)。 - **字段类型与存储精度**: - 货币与计费:严禁使用浮点数,必须使用高精度定点数(DECIMAL/NUMERIC)或以最小货币单位存储为大整型(如分、美分)。 - 时间字段:所有业务时间必须明确存储时区或统一使用 UTC 时间戳。 - 状态与枚举:评估使用数据库原生 ENUM(类型严格但修改列成本高)还是带检查约束(CHECK)的短字符串。 ### 2. ORM 与数据库迁移工具选型 为持久层选择合适的操作方式与演变机制: - **接入抽象层级**: - 纯 SQL 驱动 / 查询构建器:对生成的 SQL 具备完全控制力,心智模型透明,适合复杂查询与追求极致性能的系统。 - 类型安全 ORM:通过 Schema 自动生成编程语言类型,提供编译期保障;但需要防范 N+1 查询与过度封装。 - **迁移(Migration)规范与版本管理**: - 迁移文件不可变:已合并入主干或已在任何共享环境执行过的迁移文件绝对禁止二次修改;发现错误只能追加新的修复迁移。 - 迁移回滚方案:每个前进迁移(up)原则上都应具备对应的回滚逻辑(down),或者确认该变更为不可逆变更。 - 零停机平滑演进原则(Expand and Contract): - 严禁一次性重命名生产运行中的列或表。 - 字段变更分三步走:先扩(增加新字段并双写)→ 迁移历史数据 → 后缩(业务切换读新字段,最后删除旧字段)。 - 新增列如果无默认值,必须允许为 NULL,避免锁大表阻断写入。 ### 3. 种子数据(Seed)与测试固件 为开发环境、测试流水线与生产初始化建立基线数据: - **数据层级区分**: - 系统元数据(System Fixtures):系统运行必需的基础数据(如预设角色、系统权限、国别代码),随迁移或初始化脚本确定性写入。 - 开发用例种子(Development Seeds):模拟真实业务的多样化数据(包含多种边缘状态与关联记录),便于本地快速联调。 - 自动化测试固件(Test Fixtures):测试用例独占的极简数据,保证测试断言的确定性。 - **幂等性与写入安全**: - 种子脚本必须支持重复安全运行,使用 `upsert`(存在则更新或跳过),不得因重复执行抛出主键冲突。 - 环境隔离防护:在写入脚本入口严格校验当前数据库连接环境,绝对禁止将测试种子意外刷入生产数据库。 - 脱敏合规:严禁将生产环境的真实用户隐私数据作为开发种子直接导出。 ## 产出 每次表结构变更都必须落到一份迁移文件里,且有对应的 up/down 或明确标注不可逆。不接受"先手动改数据库,之后再补迁移"的顺序。 主键策略、是否软删除、规范化程度这类一旦选定就难以更改的决策,用 `domain-modeling` skill 记一条 ADR;日常字段增减不需要。