提交文件

This commit is contained in:
2026-02-28 15:16:15 +08:00
parent 1a4e50e0a4
commit 44f250f58e
159 changed files with 61268 additions and 0 deletions

View File

@@ -0,0 +1,507 @@
# 索引与约束设计
<cite>
**本文引用的文件**
- [models.py](file://backend/app/models/models.py)
- [finance.py](file://backend/app/models/finance.py)
- [001_initial.py](file://backend/alembic/versions/001_initial.py)
- [002_template.py](file://backend/alembic/versions/002_template.py)
- [database.py](file://backend/app/core/database.py)
- [config.py](file://backend/app/core/config.py)
- [database.md](file://docs/database.md)
- [init_db.py](file://backend/init_db.py)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件聚焦于该医院绩效系统的数据库索引与约束设计,系统采用 SQLAlchemy ORM + Alembic 进行模型定义与迁移,结合 PostgreSQL 异步驱动,围绕“科室—员工—考核—指标—工资—计划—模板—菜单—财务”等核心业务实体,系统化梳理主键、外键、唯一索引、复合索引、检查约束的设计原则与性能影响,并给出查询优化建议与并发控制考虑。
## 项目结构
- 数据模型集中于 models 目录,通过 Base 声明式基类统一建模。
- Alembic 版本化迁移文件定义了初始表结构与索引。
- 配置模块提供数据库连接参数与池化配置。
- 文档目录包含数据库 ER 图与表结构说明。
```mermaid
graph TB
subgraph "模型层"
M1["models.py<br/>核心业务模型"]
M2["finance.py<br/>财务核算模型"]
end
subgraph "迁移层"
V1["001_initial.py<br/>初始版本"]
V2["002_template.py<br/>模板扩展"]
end
subgraph "运行时"
C["config.py<br/>配置"]
D["database.py<br/>引擎/会话"]
I["init_db.py<br/>初始化脚本"]
end
subgraph "文档"
DOC["database.md<br/>ER图与表说明"]
end
M1 --> V1
M2 --> V2
V1 --> D
V2 --> D
C --> D
I --> D
DOC -.参考.-> M1
```
图表来源
- [models.py](file://backend/app/models/models.py#L62-L438)
- [finance.py](file://backend/app/models/finance.py#L45-L79)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L21-L183)
- [002_template.py](file://backend/alembic/versions/002_template.py#L21-L96)
- [database.py](file://backend/app/core/database.py#L9-L39)
- [config.py](file://backend/app/core/config.py#L18-L22)
- [database.md](file://docs/database.md#L1-L286)
章节来源
- [models.py](file://backend/app/models/models.py#L1-L438)
- [finance.py](file://backend/app/models/finance.py#L1-L79)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L1-L183)
- [002_template.py](file://backend/alembic/versions/002_template.py#L1-L96)
- [database.py](file://backend/app/core/database.py#L1-L39)
- [config.py](file://backend/app/core/config.py#L1-L47)
- [database.md](file://docs/database.md#L1-L286)
## 核心组件
- 主键与自增:多数表使用整型自增主键,确保全局唯一性与插入性能。
- 外键约束:通过 ForeignKey 映射,形成稳定的父子关系与引用完整性。
- 唯一约束:对业务唯一字段(如科室编码、员工工号、指标编码、用户名、模板编码)施加唯一约束,避免重复。
- 索引策略:针对高频过滤/连接/排序字段建立单列索引;对多条件组合查询建立复合索引;对枚举字段建立索引提升筛选效率。
- 检查约束:对数值范围进行约束(如权重>0、金额>=0保证数据质量与业务规则一致性。
章节来源
- [models.py](file://backend/app/models/models.py#L62-L438)
- [finance.py](file://backend/app/models/finance.py#L45-L79)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L21-L183)
- [002_template.py](file://backend/alembic/versions/002_template.py#L21-L96)
## 架构总览
系统采用分层架构ORM 层负责模型映射与约束声明,迁移层负责表结构演进,运行时提供异步连接与会话管理。
```mermaid
graph LR
A["前端(Vue)"] --> B["后端(FastAPI)"]
B --> C["服务层"]
C --> D["ORM(SQLAlchemy)"]
D --> E["数据库(PostgreSQL)"]
D --> F["索引/约束"]
```
图表来源
- [database.py](file://backend/app/core/database.py#L9-L39)
- [models.py](file://backend/app/models/models.py#L1-L438)
## 详细组件分析
### 科室表departments
- 主键id自增
- 唯一索引code科室编码
- 单列索引dept_type按类型过滤、parent_id树形结构查询
- 外键parent_id 自引用(树形组织)
- 设计要点dept_type 用于快速筛选不同类型的科室parent_id 支持层级查询code 唯一保证业务唯一性。
```mermaid
erEntity
"departments" {
id : integer PK
code : varchar(20) UK
dept_type : enum
parent_id : integer FK
level : integer
sort_order : integer
is_active : boolean
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L62-L86)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L22-L41)
章节来源
- [models.py](file://backend/app/models/models.py#L62-L86)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L22-L41)
### 员工表staff
- 主键id自增
- 唯一索引employee_id工号
- 单列索引department_id按科室统计/查询、status按状态筛选
- 外键department_id → departments.id
- 设计要点department_id 与 status 的索引支持按科室聚合与状态筛选unique 约束保证工号唯一。
```mermaid
erEntity
"staff" {
id : integer PK
employee_id : varchar(20) UK
department_id : integer FK
status : enum
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L88-L114)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L42-L64)
章节来源
- [models.py](file://backend/app/models/models.py#L88-L114)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L42-L64)
### 考核指标表indicators
- 主键id自增
- 唯一索引code指标编码
- 单列索引indicator_type按类型筛选
- 检查约束weight > 0权重必须为正数
- 设计要点:唯一编码保证业务唯一;按类型索引支持快速筛选;检查约束保证权重合法性。
```mermaid
erEntity
"indicators" {
id : integer PK
code : varchar(20) UK
indicator_type : enum
weight : numeric(5,2)
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L117-L146)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L66-L85)
章节来源
- [models.py](file://backend/app/models/models.py#L117-L146)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L66-L85)
### 考核记录表assessments
- 主键id自增
- 单列索引staff_id按员工查询、status按状态筛选
- 复合索引period_year + period_month按年月组合查询
- 外键staff_id → staff.idassessor_id/reviewer_id → staff.id自关联
- 设计要点复合索引支持按年月快速定位staff_id 索引支撑员工维度统计status 索引便于流程状态筛选。
```mermaid
erEntity
"assessments" {
id : integer PK
staff_id : integer FK
period_year : integer
period_month : integer
status : enum
assessor_id : integer FK
reviewer_id : integer FK
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L149-L178)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L87-L112)
章节来源
- [models.py](file://backend/app/models/models.py#L149-L178)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L87-L112)
### 考核明细表assessment_details
- 主键id自增
- 单列索引assessment_id按考核记录查询明细、indicator_id按指标查询明细
- 外键assessment_id → assessments.idindicator_id → indicators.id
- 设计要点:双外键字段分别建立单列索引,满足“按记录查明细”和“按指标查明细”的常见查询模式。
```mermaid
erEntity
"assessment_details" {
id : integer PK
assessment_id : integer FK
indicator_id : integer FK
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L181-L202)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L114-L131)
章节来源
- [models.py](file://backend/app/models/models.py#L181-L202)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L114-L131)
### 工资核算表salary_records
- 主键id自增
- 单列索引staff_id按员工查询、status按状态筛选
- 复合索引period_year + period_month按年月组合查询
- 外键staff_id → staff.id
- 设计要点复合索引支持按年月快速检索staff_id 索引支撑员工维度统计。
```mermaid
erEntity
"salary_records" {
id : integer PK
staff_id : integer FK
period_year : integer
period_month : integer
status : varchar(20)
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L205-L230)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L133-L154)
章节来源
- [models.py](file://backend/app/models/models.py#L205-L230)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L133-L154)
### 用户表users
- 主键id自增
- 唯一索引username用户名
- 外键staff_id → staff.id可选关联
- 设计要点username 唯一索引支持登录认证staff_id 外键实现用户与员工的弱关联。
```mermaid
erEntity
"users" {
id : integer PK
username : varchar(50) UK
staff_id : integer FK
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L244-L260)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L156-L172)
章节来源
- [models.py](file://backend/app/models/models.py#L244-L260)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L156-L172)
### 绩效计划表performance_plans
- 主键id自增
- 唯一索引plan_code计划编码
- 单列索引plan_level、plan_year、department_id、status
- 外键department_id → departments.idstaff_id → staff.idsubmitter_id/approver_id → users.idparent_plan_id → performance_plans.id自关联
- 设计要点:多维索引支持按层级、年份、状态、科室等条件筛选;唯一编码保证业务唯一性。
```mermaid
erEntity
"performance_plans" {
id : integer PK
plan_code : varchar(50) UK
plan_level : enum
plan_year : integer
department_id : integer FK
status : enum
parent_plan_id : integer FK
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L270-L311)
章节来源
- [models.py](file://backend/app/models/models.py#L270-L311)
### 计划-指标关联表plan_kpi_relations
- 主键id自增
- 单列索引plan_id、indicator_id
- 复合唯一索引plan_id + indicator_id唯一关联
- 外键plan_id → performance_plans.idindicator_id → indicators.id
- 设计要点:复合唯一索引防止重复关联;单列索引支撑按计划或指标查询。
```mermaid
erEntity
"plan_kpi_relations" {
id : integer PK
plan_id : integer FK
indicator_id : integer FK
plan_id+indicator_id : unique
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L314-L338)
- [002_template.py](file://backend/alembic/versions/002_template.py#L41-L63)
章节来源
- [models.py](file://backend/app/models/models.py#L314-L338)
- [002_template.py](file://backend/alembic/versions/002_template.py#L41-L63)
### 模板-指标关联表template_indicators
- 主键id自增
- 单列索引template_id、indicator_id
- 复合唯一索引template_id + indicator_id唯一关联
- 外键template_id → indicator_templates.idindicator_id → indicators.id
- 设计要点:与计划-指标关联一致的索引策略,确保模板维度的高效查询。
```mermaid
erEntity
"template_indicators" {
id : integer PK
template_id : integer FK
indicator_id : integer FK
template_id+indicator_id : unique
created_at : datetime
updated_at : datetime
}
```
图表来源
- [models.py](file://backend/app/models/models.py#L411-L437)
- [002_template.py](file://backend/alembic/versions/002_template.py#L41-L63)
章节来源
- [models.py](file://backend/app/models/models.py#L411-L437)
- [002_template.py](file://backend/alembic/versions/002_template.py#L41-L63)
### 财务核算表department_finances
- 主键id自增
- 单列索引department_id、finance_type、category
- 复合索引period_year + period_month按年月组合查询
- 检查约束amount >= 0金额非负
- 外键department_id → departments.id
- 设计要点:多维索引支持按科室、类型、类别、期间的高效查询;检查约束保证财务数据的正向性。
```mermaid
erEntity
"department_finances" {
id : integer PK
department_id : integer FK
period_year : integer
period_month : integer
finance_type : enum
category : varchar(50)
amount : numeric(12,2)
created_at : datetime
updated_at : datetime
}
```
图表来源
- [finance.py](file://backend/app/models/finance.py#L45-L74)
章节来源
- [finance.py](file://backend/app/models/finance.py#L45-L74)
## 依赖关系分析
- 模型层通过 __table_args__ 声明索引与约束,迁移层通过 Alembic 在数据库层面落地。
- 外键关系形成稳定的层次结构(如 departments 树形、assessments 与 staff 的自关联)。
- 初始化脚本在首次启动时创建表结构并注入基础数据。
```mermaid
graph TB
subgraph "模型定义"
MD["models.py"]
MF["finance.py"]
end
subgraph "迁移执行"
MI["001_initial.py"]
MT["002_template.py"]
end
subgraph "运行时"
DB["database.py"]
CFG["config.py"]
INIT["init_db.py"]
end
MD --> MI
MF --> MT
MI --> DB
MT --> DB
CFG --> DB
INIT --> DB
```
图表来源
- [models.py](file://backend/app/models/models.py#L62-L438)
- [finance.py](file://backend/app/models/finance.py#L45-L79)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L21-L183)
- [002_template.py](file://backend/alembic/versions/002_template.py#L21-L96)
- [database.py](file://backend/app/core/database.py#L9-L39)
- [config.py](file://backend/app/core/config.py#L18-L22)
- [init_db.py](file://backend/init_db.py#L11-L83)
章节来源
- [models.py](file://backend/app/models/models.py#L62-L438)
- [finance.py](file://backend/app/models/finance.py#L45-L79)
- [001_initial.py](file://backend/alembic/versions/001_initial.py#L21-L183)
- [002_template.py](file://backend/alembic/versions/002_template.py#L21-L96)
- [database.py](file://backend/app/core/database.py#L9-L39)
- [config.py](file://backend/app/core/config.py#L18-L22)
- [init_db.py](file://backend/init_db.py#L11-L83)
## 性能考量
- 索引选择原则
- 单列索引:适用于等值/范围查询的过滤字段(如 status、dept_type、indicator_type
- 复合索引:适用于多条件组合查询(如 assessments 的 period_year + period_monthsalary_records 的 period_year + period_monthfinance 的 period_year + period_month
- 唯一索引保证业务唯一性code、employee_id、username、plan_code、模板-指标唯一组合)。
- 查询优化建议
- 使用复合索引覆盖多条件过滤,减少回表与排序开销。
- 对枚举字段建立索引,提升 IN/等值过滤效率。
- 尽量避免 SELECT *,仅选择必要列,降低 IO。
- 对大表的分页查询配合 ORDER BY + LIMIT确保 ORDER BY 列命中索引。
- 并发控制
- 使用数据库事务隔离级别与锁策略,避免写放大与死锁。
- 对高并发写入场景,合理拆分热点表或引入分区(如按年/月分区)。
- 控制批量写入批次大小,避免长事务占用资源。
- 数据完整性
- 外键约束保证引用完整性;唯一约束保证业务唯一性;检查约束保证数值范围合法。
- 在 ORM 层与数据库层双重约束,确保数据一致性。
[本节为通用性能指导,不直接分析具体文件]
## 故障排查指南
- 索引未生效
- 检查查询条件是否与索引列顺序匹配(复合索引前缀匹配)。
- 使用 EXPLAIN/ANALYZE 分析执行计划,确认索引扫描路径。
- 唯一冲突
- 当插入重复唯一键时,捕获数据库异常并提示用户修正(如重复工号、重复指标编码)。
- 外键约束失败
- 确认被引用记录存在且状态有效;检查删除/更新策略RESTRICT/CASCADE/SET NULL
- 检查约束失败
- 校验输入数据是否满足约束条件(如权重>0、金额>=0在业务层提前校验减少数据库往返。
[本节为通用排查建议,不直接分析具体文件]
## 结论
该系统在索引与约束设计上遵循“业务唯一性优先、高频查询覆盖、枚举与复合索引配合”的原则,结合外键与检查约束,有效保障了数据完整性与查询性能。建议在后续迭代中持续关注查询执行计划与热点表,适时引入分区与物化视图,进一步提升大规模数据下的响应能力。
[本节为总结性内容,不直接分析具体文件]
## 附录
- 数据库连接与池化配置
- 数据库 URL、连接池大小与溢出配置确保高并发下的稳定性。
- 初始化脚本
- 首次启动自动创建表结构并注入基础数据,便于开发与测试环境快速就绪。
章节来源
- [config.py](file://backend/app/core/config.py#L18-L22)
- [init_db.py](file://backend/init_db.py#L11-L83)