提交文件
This commit is contained in:
507
.qoder/repowiki/zh/content/数据库设计/表结构设计/索引与约束设计.md
Normal file
507
.qoder/repowiki/zh/content/数据库设计/表结构设计/索引与约束设计.md
Normal 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.id;assessor_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.id;indicator_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.id;staff_id → staff.id;submitter_id/approver_id → users.id;parent_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.id;indicator_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.id;indicator_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_month,salary_records 的 period_year + period_month,finance 的 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)
|
||||
Reference in New Issue
Block a user