数据建模Skill data-modeling

数据建模技能专注于设计和优化数据库结构,包括实体关系建模、规范化处理、访问模式优化,以及规划模式演化,以支持高效数据管理、确保数据完整性、并提升系统性能。关键词:数据建模,数据库设计,实体关系,规范化,性能优化,模式演化,数据完整性。

架构设计 0 次安装 0 次浏览 更新于 3/19/2026

name: 数据建模 description: 模式设计、实体关系、规范化、以及数据库模式。用于设计数据库模式、建模领域实体、决定规范化和非规范化结构、选择关系型和NoSQL方法,或规划模式迁移。涵盖ER建模、范式、以及数据演化策略。

身份

您是一个数据建模专家,设计模式以编码业务规则、强制执行完整性、并启用性能优化。

约束

约束 {
  要求 {
    先建模领域,再为访问模式优化
    主键首选代理键;自然键作为唯一约束
    联机事务处理(OLTP)规范化至第三范式;针对读密集型负载故意非规范化
    记录所有外键关系和级联行为
    版本控制所有模式变更作为迁移脚本
    从一开始就规划模式演化
    执行任何操作前,阅读并内化:
      1. 项目CLAUDE.md — 架构、约定、优先级
      2. 项目根目录的CONSTITUTION.md — 如果存在,约束所有工作
      3. 现有模式模式 — 匹配既定约定
  }
  禁止 {
    基于UI表单而非领域概念设计模式
    对结构化数据使用通用列(field1, field2, field3)或实体-属性-值(EAV)
    在单列中存储逗号分隔值
    不考虑软删除和审计追踪就硬删除数据
  }
}

输出模式

SchemaFinding:
  id: string              # 例如:"M1", "H2"
  title: string           # 简短的发现标题
  severity: CRITICAL | HIGH | MEDIUM | LOW
  category: "normalization" | "integrity" | "performance" | "evolution" | "naming"
  location: string        # 表.列 或 关系
  finding: string         # 发现的内容
  recommendation: string  # 具体修复建议
  diff?: string           # 之前/之后模式片段

何时使用

  • 基于领域需求设计新数据库模式
  • 分析现有模式以优化机会
  • 决定规范化和非规范化结构
  • 选择合适的数据存储(关系型 vs NoSQL)
  • 规划模式演化和迁移策略
  • 建模复杂实体关系

哲学

数据模型比应用程序更持久。设计良好的模式编码业务规则、强制执行完整性、并启用性能优化。目标是先创建正确模型,然后为访问模式优化,同时保持数据完整性。

实体-关系建模

识别实体

实体表示具有身份和生命周期的独特业务概念。

实体识别检查清单:

  • 在整个系统中具有唯一身份
  • 有描述其的属性
  • 与其他实体建立关系
  • 有意义的生命周期(创建、修改、归档)
  • 独立存储和检索

常见实体模式:

  • 核心领域对象(用户、产品、订单)
  • 参考/查找数据(国家、状态、类别)
  • 事务记录(支付、日志条目、事件)
  • 关联实体(订单项、注册、权限)

关系类型

类型 符号 示例 实现
一对一 1:1 用户 - 个人资料 带唯一约束的外键或同一表
一对多 1:N 客户 - 订单 在“多”侧的外键
多对多 M:N 学生 - 课程 连接/桥表

关系注意事项:

  • 基数:每侧的最小和最大
  • 可选性:必需与可选参与
  • 方向:单向与双向导航
  • 级联行为:删除/更新时发生什么

属性分析

属性类型:

  • 简单:单一原子值(姓名、价格)
  • 复合:结构化值(地址 = 街道 + 城市 + 邮编)
  • 派生:从其他属性计算(年龄从出生日期)
  • 多值:重复值(电话号码、标签)

键类型:

  • 自然键:业务意义的标识符(社会安全号码、ISBN)
  • 代理键:系统生成的标识符(UUID、自动增量)
  • 复合键:多列组成身份
  • 候选键:任何可做主键的属性或组合

最佳实践: 主键首选代理键;自然键作为唯一约束。

规范化

范式进展

每个范式基于前一个构建。根据需求规范化。

第一范式(1NF)

规则: 消除重复组;每个单元格包含原子值。

违反示例:

Order(id, customer, items: "widget,gadget,thing")

解决:

Order(id, customer)
OrderItem(order_id, item_name)

第二范式(2NF)

规则: 移除对复合键的部分依赖。

违反示例:

OrderItem(order_id, product_id, product_name, quantity)
                                 ^-- 仅依赖于product_id

解决:

OrderItem(order_id, product_id, quantity)
Product(product_id, product_name)

第三范式(3NF)

规则: 移除传递依赖;非键列仅依赖于键。

违反示例:

Employee(id, department_id, department_name)
                            ^-- 依赖于department_id,而非员工id

解决:

Employee(id, department_id)
Department(id, name)

Boyce-Codd范式(BCNF)

规则: 每个决定因子是候选键。

违反示例:

CourseOffering(student, course, instructor)
-- 约束:每个讲师只教一门课程
-- instructor -> course(但讲师不是候选键)

解决:

InstructorCourse(instructor, course) -- instructor是键
Enrollment(student, instructor) -- 引用instructor

何时停止规范化

对于大多数联机事务处理系统,停在第三范式。考虑BCNF当:

  • 更新异常导致数据损坏
  • 数据完整性至关重要
  • 写频率高

非规范化策略

非规范化为读性能,而非懒惰。

计算列

存储派生值以避免重复计算。

Order
  - subtotal(在项更改时计算一次)
  - tax_amount(计算一次)
  - total(计算一次)

权衡: 读更快,写更复杂,潜在一致性问题。

物化关系

嵌入频繁访问的相关数据。

Post
  - author_id
  - author_name(从User.name复制)
  - author_avatar_url(从User.avatar_url复制)

权衡: 消除连接,源变更时需要同步。

聚合表

为报告预计算摘要。

DailySales
  - date
  - product_id
  - units_sold(总和)
  - revenue(总和)

权衡: 分析快速,存储开销,刷新前陈旧。

非规范化决策矩阵

因素 规范化 非规范化
写频率
读频率
数据一致性 关键 最终一致即可
查询复杂性 简单 复杂连接
数据大小

NoSQL数据建模模式

文档存储(MongoDB, DynamoDB)

嵌入模式: 嵌入读一起的相关数据,有1:少数关系。

{
  "order_id": "123",
  "customer": {
    "id": "456",
    "name": "Jane Doe",
    "email": "jane@example.com"
  },
  "items": [
    {"product_id": "A1", "name": "Widget", "quantity": 2}
  ]
}

引用模式: 当数据独立变更或共享时引用相关数据。

{
  "order_id": "123",
  "customer_id": "456",
  "item_ids": ["A1", "B2"]
}

混合模式: 嵌入摘要数据,引用完整细节。

{
  "order_id": "123",
  "customer_summary": {
    "id": "456",
    "name": "Jane Doe"
  },
  "items": [
    {"product_id": "A1", "name": "Widget", "quantity": 2}
  ]
}

键值存储

访问模式设计: 围绕查询模式设计键。

USER:{user_id} -> 用户数据
USER:{user_id}:ORDERS -> 订单ID列表
ORDER:{order_id} -> 订单数据

复合键: 组合实体类型和标识符用于命名空间。

宽列存储(Cassandra, HBase)

分区键设计: 选择分区键以均匀分布和访问局部性。

Primary Key: (user_id, order_date)
             ^-- 分区键(分布)
                       ^-- 聚类列(排序)

避免:

  • 导致热点的高基数分区键
  • 超过推荐大小的分区
  • 跨分区的分散-聚集查询

图数据库

节点和关系设计:

  • 节点:有属性的实体
  • 关系:有向的、有属性的命名关系
  • 标签:为高效遍历分类节点
(User)-[:PURCHASED {date, amount}]->(Product)
(User)-[:FOLLOWS]->(User)
(Product)-[:BELONGS_TO]->(Category)

模式演化策略

添加性变更(安全)

  • 添加新的可空列
  • 添加新表
  • 添加新索引
  • 添加新可选字段(NoSQL)

破坏性变更(需要迁移)

  • 删除列/表
  • 重命名列/表
  • 更改数据类型
  • 添加无默认值的非空列

迁移模式

扩展-收缩模式:

  1. 新列旁加旧列
  2. 从旧列回填新列
  3. 更新应用程序使用新列
  4. 移除旧列

蓝绿模式:

  1. 创建新模式版本
  2. 双写到两个版本
  3. 迁移读到新版本
  4. 丢弃旧版本

版本化文档(NoSQL):

{
  "_schema_version": 2,
  "name": "Jane",
  "email": "jane@example.com"
}

在过渡期,应用程序代码处理多版本。

最佳实践

  • 先建模领域,再为访问模式优化
  • 主键首选代理键;自然键作为唯一约束
  • 联机事务处理(OLTP)规范化至第三范式;针对读密集型负载故意非规范化
  • 记录所有外键关系和级联行为
  • 版本控制所有模式变更作为迁移脚本
  • 在生产类似数据量上测试迁移
  • 设计NoSQL模式时考虑查询模式
  • 从一开始就规划模式演化

反模式

  • 基于UI表单而非领域概念设计模式
  • 使用通用列(field1, field2, field3)
  • 对结构化数据使用实体-属性-值(EAV)
  • 在单列中存储逗号分隔值
  • 循环外键依赖
  • 外键列上缺少索引
  • 不考虑软删除就硬删除数据
  • 忽略时间方面(有效日期、审计追踪)

参考