name: 数据建模 description: 使用实体关系图(ERD)、数据字典和概念/逻辑/物理模型进行数据建模。文档化数据结构、关系和属性。 allowed-tools: Read, Glob, Grep, Task, Skill
数据建模
何时使用此技能
在以下情况下使用此技能:
- 数据建模任务 - 使用实体关系图(ERD)、数据字典和概念/逻辑/物理模型进行数据建模。文档化数据结构、关系和属性。
- 规划或设计 - 需要数据建模方法的指导
- 最佳实践 - 希望遵循既定的模式和标准
概述
使用实体关系图(ERD)、数据字典和结构化数据模型创建和文档化数据结构。支持概念、逻辑和物理建模级别,用于数据库设计和数据架构。
什么是数据建模?
数据建模创建数据和数据关系的视觉和结构化表示。它文档化:
- 实体:存储数据的事物
- 属性:实体的属性
- 关系:实体如何连接
- 约束:管理数据的规则
建模级别
| 级别 | 目的 | 受众 | 细节 |
|---|---|---|---|
| 概念 | 业务概念 | 业务用户 | 实体、高级关系 |
| 逻辑 | 数据结构 | 分析师、设计师 | 实体、属性、所有关系 |
| 物理 | 实现 | 开发人员、DBA | 表、列、类型、索引 |
概念模型
业务概念的高级视图:
- 仅主要实体
- 关键关系
- 无属性(或最小)
- 无技术细节
逻辑模型
技术独立的数据结构:
- 所有实体和属性
- 主键和外键
- 所有关系与基数
- 应用规范化
- 无物理实现细节
物理模型
数据库特定的实现:
- 表名(物理命名)
- 列名和数据类型
- 索引和约束
- 视图和存储过程
- 数据库特定功能
ERD 符号
实体(矩形)
实体表示存储数据的事物。
┌─────────────────┐
│ 客户 │
├─────────────────┤
│ customer_id PK │
│ name │
│ email │
│ created_at │
└─────────────────┘
实体类型:
| 类型 | 描述 | 示例 |
|---|---|---|
| 强 | 独立存在 | 客户、产品 |
| 弱 | 依赖另一个实体 | 订单行(依赖订单) |
| 关联 | 解决多对多关系 | 注册(学生-课程) |
属性
| 类型 | 符号 | 描述 |
|---|---|---|
| 主键(PK) | 下划线/PK | 唯一标识符 |
| 外键(FK) | FK | 引用另一个实体 |
| 必需 | * 或 NOT NULL | 必须有值 |
| 可选 | ○ 或 NULL | 可能为空 |
| 派生 | / | 从其他属性计算 |
| 复合 | {attrs} | 由子属性组成 |
| 多值 | [attr] | 可以有多个值 |
关系(线)
符号风格:
| 风格 | 使用于 |
|---|---|
| Chen | 学术、概念 |
| Crow’s Foot | 行业标准 |
| UML | 软件设计 |
| IDEF1X | 政府、结构化 |
Crow’s Foot 符号:
| 符号 | 含义 |
|---|---|
── |
一(必需) |
──○ |
零或一(可选) |
──< |
多 |
──○< |
零或多 |
基数
| 符号 | 含义 | 示例 |
|---|---|---|
| 1:1 | 一对一 | 员工 → 工作站 |
| 1:M | 一对多 | 客户 → 订单 |
| M:N | 多对多 | 学生 ↔ 课程 |
读取基数:
“一个[实体 A] 有 [最小]…[最大] [实体 B]”
示例:“一个客户有 0…多 订单”
工作流程
阶段 1:识别实体
步骤 1:从需求中提取名词
从业务需求中识别:
- 业务跟踪的事物
- 业务规则的主体
- 数据的来源和目标
步骤 2:筛选候选
| 保留 | 排除 |
|---|---|
| 独立概念 | 属性(实体的属性) |
| 有多个实例的事物 | 同义词(相同概念,不同名称) |
| 需要数据存储的事物 | 动作(动词,非名词) |
步骤 3:文档化实体
## 实体
| 实体 | 描述 | 示例 |
|--------|-------------|---------|
| 客户 | 购买的个人或组织 | 张三、Acme 公司 |
| 订单 | 购买交易 | 订单 #12345 |
| 产品 | 可销售的商品 | 小部件、小工具 |
阶段 2:定义属性
步骤 1:为每个实体列出属性
对于每个实体,识别:
- 我们需要知道关于这个实体的什么?
- 什么唯一标识它?
- 业务引用什么数据?
步骤 2:分类属性
| 属性 | 类型 | 必需 | 备注 |
|---|---|---|---|
| customer_id | PK | 是 | 代理键 |
| 唯一 | 是 | 业务键 | |
| name | 字符串 | 是 | |
| phone | 字符串 | 否 | 可选 |
步骤 3:识别键
- 主键(PK):唯一标识符
- 自然键:业务有意义的标识符
- 代理键:系统生成的标识符
- 复合键:多个属性组合
阶段 3:定义关系
步骤 1:识别连接
对于每对实体:
- 有业务连接吗?
- 关系的性质是什么?
- 基数是什么?
步骤 2:文档化关系
## 关系
| 关系 | 从 | 到 | 基数 | 描述 |
|--------------|------|-----|-------------|-------------|
| 下 | 客户 | 订单 | 1:M | 客户下订单 |
| 包含 | 订单 | 产品 | M:N | 订单包含产品 |
步骤 3:解决多对多
多对多关系需要关联实体:
学生 ──M:N── 课程
变为:
学生 ──1:M── 注册 ──M:1── 课程
阶段 4:规范化(逻辑模型)
范式:
| 形式 | 规则 | 违反示例 |
|---|---|---|
| 1NF | 原子值,无重复组 | Phone1, Phone2, Phone3 |
| 2NF | 无部分依赖 | 非键依赖复合键的一部分 |
| 3NF | 无传递依赖 | 非键依赖非键 |
| BCNF | 每个决定因素是候选键 | 候选键重叠 |
何时反规范化:
- 读取性能关键
- 报告/分析用例
- 数据仓库设计
- 有清晰权衡分析的理由
阶段 5:创建物理模型
步骤 1:映射到物理类型
| 逻辑类型 | 物理(PostgreSQL) | 物理(SQL Server) |
|---|---|---|
| String(50) | VARCHAR(50) | NVARCHAR(50) |
| Integer | INTEGER | INT |
| Decimal(10,2) | NUMERIC(10,2) | DECIMAL(10,2) |
| Date | DATE | DATE |
| Timestamp | TIMESTAMP | DATETIME2 |
| Boolean | BOOLEAN | BIT |
步骤 2:定义约束
- 主键约束
- 外键约束
- 唯一约束
- 检查约束
- 默认值
步骤 3:规划索引
- 主键(自动)
- 外键(用于连接)
- 频繁查询的列
- 覆盖索引以提高性能
输出格式
Mermaid ERD
erDiagram
客户 ||--o{ 订单 : 下
订单 ||--|{ 订单行 : 包含
产品 ||--o{ 订单行 : 包括
客户 {
int customer_id PK
string name
string email UK
date created_at
}
订单 {
int order_id PK
int customer_id FK
date order_date
decimal total
string status
}
订单行 {
int order_id PK,FK
int product_id PK,FK
int quantity
decimal unit_price
}
产品 {
int product_id PK
string name
string sku UK
decimal price
int stock_qty
}
数据字典
## 数据字典
### 客户
| 列 | 类型 | 可为空 | 键 | 默认 | 描述 |
|--------|------|------|-----|---------|-------------|
| customer_id | INT | 否 | PK | AUTO | 唯一标识符 |
| name | VARCHAR(100) | 否 | | | 客户全名 |
| email | VARCHAR(255) | 否 | UK | | 联系邮箱 |
| phone | VARCHAR(20) | 是 | | NULL | 联系电话 |
| created_at | TIMESTAMP | 否 | | NOW() | 记录创建时间 |
**索引:**
- `pk_customer` (customer_id) - 主键
- `uk_customer_email` (email) - 唯一
- `ix_customer_name` (name) - 搜索
**约束:**
- 邮箱格式验证(CHECK)
- 名称长度至少 2 字符
结构化数据(YAML)
data_model:
name: "电子商务"
version: "1.0"
date: "2025-01-15"
level: "逻辑" # 概念、逻辑、物理
analyst: "数据建模师"
entities:
- name: "客户"
type: "强"
description: "购买的个人或组织"
attributes:
- name: "customer_id"
type: "整数"
key: "主键"
required: true
generated: true
- name: "email"
type: "字符串"
length: 255
key: "唯一"
required: true
- name: "name"
type: "字符串"
length: 100
required: true
- name: "订单"
type: "强"
description: "购买交易"
attributes:
- name: "order_id"
type: "整数"
key: "主键"
required: true
- name: "customer_id"
type: "整数"
key: "外键"
references: "客户.customer_id"
required: true
relationships:
- name: "下"
from: "客户"
to: "订单"
cardinality: "1:M"
from_participation: "可选" # 0..1
to_participation: "必需" # 1..M
description: "客户下订单"
constraints:
- entity: "客户"
type: "检查"
expression: "LENGTH(name) >= 2"
description: "名称最小长度"
indexes:
- entity: "订单"
name: "ix_order_date"
columns: ["order_date"]
purpose: "日期范围查询"
叙述摘要
## 数据模型:电子商务
**版本:** 1.0
**日期:** [ISO 日期]
**级别:** 逻辑
### 实体摘要
| 实体 | 描述 | 关键关系 |
|--------|-------------|-------------------|
| 客户 | 购买者 | 下订单 |
| 订单 | 交易 | 属于客户、包含产品 |
| 产品 | 可销售商品 | 包含在订单中 |
| 订单行 | 订单详情 | 链接订单到产品 |
### 关键关系
1. **客户 → 订单(1:M)**
- 一个客户可以下多个订单
- 每个订单属于一个客户
2. **订单 ↔ 产品(M:N 通过订单行)**
- 一个订单可以包含多个产品
- 一个产品可以出现在多个订单中
### 数据完整性规则
1. 订单不能没有客户存在
2. 订单行必须引用有效的订单和产品
3. 库存数量不能为负
4. 邮箱必须每个客户唯一
### 备注
- 考虑按日期分区订单以处理大容量
- 产品价格存储在订单行中以保持历史准确性
常见模式
继承(子类型/超类型)
erDiagram
人 ||--o| 员工 : "是"
人 ||--o| 客户 : "是"
人 {
int person_id PK
string name
string email
}
员工 {
int person_id PK,FK
date hire_date
decimal salary
}
客户 {
int person_id PK,FK
string company
decimal credit_limit
}
自引用
erDiagram
员工 ||--o{ 员工 : "管理"
员工 {
int employee_id PK
string name
int manager_id FK
}
审计跟踪
erDiagram
实体 ||--o{ 实体历史 : "有历史"
实体 {
int id PK
string data
timestamp updated_at
}
实体历史 {
int history_id PK
int entity_id FK
string data
timestamp valid_from
timestamp valid_to
string changed_by
}
集成
上游
- 需求 - 数据需求来源
- 领域故事讲述 - 领域概念
- 过程建模 - 过程中的数据
下游
- 数据库设计 - 物理实现
- API 设计 - 数据契约
- 集成 - 数据交换
相关技能
过程建模- 数据的过程上下文旅程映射- 客户数据接触点决策分析- 数据驱动决策能力映射- 数据支持能力
版本历史
- v1.0.0 (2025-12-26):初始发布