Files
student_manage_system/docs/03-database-design.md
2026-09-23 10:43:14 +08:00

437 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 学生管理系统 — 数据库设计文档
## 1. 数据库概述
| 属性 | 说明 |
|------|------|
| 数据库名 | `sms`(学生管理系统 Student Manage System) |
| 存储引擎 | InnoDB |
| 字符集 | utf8mb4 |
| 默认排序规则 | utf8mb4_unicode_ci |
| 通用字段方案 | `id`、`create_time`、`update_time`、`is_deleted`、`delete_time` |
---
## 2. ER 关系图
```
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ teachers │ │ classes │ │ students │
├──────────────────┤ ├──────────────────┤ ├──────────────────┤
│ id (PK) │ │ id (PK) │ │ id (PK) │
│ num (UK) │ │ num (UK) │ │ num (UK) │
│ name │ 1:N │ name │ 1:N │ name │
│ age │ ----> │ class_start_time │ ----> │ age │
│ sex │ │ │ │ sex │
│ home_place │ │ head_teacher_id │ │ home_place │
│ college │ │ coach_teacher_id │ │ college │
│ specialty │ │ tutor_teacher_id │ │ specialty │
│ enrollment_time │ └──────┬───────────┘ │ enrollment_time │
│ graduate_time │ │ graduate_time │
│ education │ │ education │
│ work_experience │ │ │
│ coach_area │ │ create_time │
│ │ │ update_time │
│ create_time │ ------------------│ is_deleted │
│ update_time │ │ │ delete_time │
│ is_deleted │ │ 1:N └──────────────────┘
│ delete_time │ ▼ | 1:1
└──────────────────┘ ┌──────────────────┐ ┌──────────────────┐
│ scores │ │ employment │
├──────────────────┤ ├──────────────────┤
│ id (PK) │ │ id (PK) │
│ sid (FK→students)│ │ sid (FK→students)│
│ num │ │ class_id (FK) │
│ score │ │ employment_open │
│ │ │ _time │
│ create_time │ │ offer_recived │
│ update_time │ │ _time │
│ is_deleted │ │ employment_comp │
│ delete_time │ │ any │
└──────────────────┘ │ employment_salar │
│ y │
│ │
│ create_time │
│ update_time │
│ is_deleted │
│ delete_time │
└──────────────────┘
```
---
## 3. 表结构详述
### 3.1 teachers — 教师表
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | INT | PK, AUTO_INCREMENT | 主键 |
| num | VARCHAR(30) | UNIQUE, NOT NULL, INDEX | 教师编号 |
| name | VARCHAR(30) | NOT NULL | 姓名 |
| age | INT | DEFAULT 18 | 年龄 |
| sex | INT | DEFAULT 0 | 性别:0未知 1男 2女 |
| home_place | VARCHAR(50) | NULL | 家乡 |
| college | VARCHAR(50) | NULL | 毕业院校 |
| specialty | VARCHAR(50) | NULL | 专业 |
| enrollment_time | DATETIME | NULL | 入学时间 |
| graduate_time | DATETIME | NULL | 毕业时间 |
| education | VARCHAR(50) | NULL | 学历 |
| work_experience | TEXT | NULL | 工作经验 |
| coach_area | VARCHAR(50) | NULL | 教学方向:应用/项目/算法 |
| create_time | DATETIME | NOT NULL | 创建时间 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| is_deleted | BOOLEAN | DEFAULT FALSE | 软删除标志 |
| delete_time | DATETIME | NULL | 删除时间 |
**索引:**
```sql
PRIMARY KEY (id),
UNIQUE KEY uk_tnum (num),
KEY idx_num (num)
```
**外键:** 无(teachers 作为被引用方)
---
### 3.2 classes — 班级表
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | INT | PK, AUTO_INCREMENT | 主键 |
| num | VARCHAR(30) | UNIQUE, NOT NULL, INDEX | 班级编号 |
| name | VARCHAR(30) | NOT NULL | 班级名称 |
| class_start_time | DATETIME | NULL | 开课时间 |
| head_teacher_id | INT | NULL, FK→teachers.id | 班主任 ID |
| coach_teacher_id | INT | NULL, FK→teachers.id | 授课老师 ID |
| tutor_teacher_id | INT | NULL, FK→teachers.id | 助教老师 ID |
| create_time | DATETIME | NOT NULL | 创建时间 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| is_deleted | BOOLEAN | DEFAULT FALSE | 软删除标志 |
| delete_time | DATETIME | NULL | 删除时间 |
**索引:**
```sql
PRIMARY KEY (id),
UNIQUE KEY uk_class_num (num),
KEY idx_head_teacher (head_teacher_id),
KEY idx_coach_teacher (coach_teacher_id),
KEY idx_tutor_teacher (tutor_teacher_id)
```
**外键:**
```sql
CONSTRAINT fk_classes_head_teacher FOREIGN KEY (head_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_classes_coach_teacher FOREIGN KEY (coach_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_classes_tutor_teacher FOREIGN KEY (tutor_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE
```
---
### 3.3 students — 学生表
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | INT | PK, AUTO_INCREMENT | 主键 |
| num | VARCHAR(30) | UNIQUE, NOT NULL, INDEX | 学生编号 |
| name | VARCHAR(30) | NOT NULL | 姓名 |
| age | INT | DEFAULT 18 | 年龄 |
| sex | INT | DEFAULT 0 | 性别:0未知 1男 2女 |
| home_place | VARCHAR(50) | NULL | 家乡 |
| college | VARCHAR(50) | NULL | 毕业院校 |
| specialty | VARCHAR(50) | NULL | 专业 |
| enrollment_time | DATETIME | NULL | 入学时间 |
| graduate_time | DATETIME | NULL | 毕业时间 |
| education | VARCHAR(50) | NULL | 学历 |
| class_id | INT | NOT NULL, DEFAULT 0, INDEX | 所属班级 ID |
| advisor_id | INT | NULL, FK→teachers.id | 顾问老师 ID |
| create_time | DATETIME | NOT NULL | 创建时间 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| is_deleted | BOOLEAN | DEFAULT FALSE | 软删除标志 |
| delete_time | DATETIME | NULL | 删除时间 |
**索引:**
```sql
PRIMARY KEY (id),
UNIQUE KEY uk_snum (num),
KEY idx_class_id (class_id),
KEY idx_advisor_id (advisor_id),
KEY idx_class_deleted (class_id, is_deleted) -- 复合索引,优化班级学生列表查询
```
**外键:**
```sql
CONSTRAINT fk_students_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT fk_students_advisor FOREIGN KEY (advisor_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE
```
> **注意**:`class_id` 使用 `ON DELETE RESTRICT`,防止误删有学生的班级。
---
### 3.4 scores — 成绩表
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | INT | PK, AUTO_INCREMENT | 主键 |
| sid | INT | NOT NULL, FK→students.id, INDEX | 学生 ID |
| num | VARCHAR(30) | NOT NULL | 考核序次(如"第一次考核") |
| score | DECIMAL(10,2) | NOT NULL | 分数 |
| create_time | DATETIME | NOT NULL | 创建时间 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| is_deleted | BOOLEAN | DEFAULT FALSE | 软删除标志 |
| delete_time | DATETIME | NULL | 删除时间 |
**索引:**
```sql
PRIMARY KEY (id),
UNIQUE KEY uk_sid_score (sid, num), -- 防止同一学生同一考核重复录入
KEY idx_sid (sid)
```
**外键:**
```sql
CONSTRAINT fk_scores_student FOREIGN KEY (sid) REFERENCES students(id) ON DELETE CASCADE ON UPDATE CASCADE
```
> 删除学生时,其所有成绩记录自动级联删除。
---
### 3.5 employment — 就业表
| 字段名 | 类型 | 约束 | 说明 |
|--------|------|------|------|
| id | INT | PK, AUTO_INCREMENT | 主键 |
| sid | INT | UNIQUE, FK→students.id | 学生 ID(一对一) |
| class_id | INT | NOT NULL, INDEX | 所属班级 ID |
| employment_open_time | DATETIME | NULL | 就业开放时间 |
| offer_recived_time | DATETIME | NULL | Offer 下发时间 |
| employment_company | VARCHAR(50) | NULL | 就业公司 |
| employment_salary | DECIMAL(20,5) | NULL | 就业薪资(月薪) |
| create_time | DATETIME | NOT NULL | 创建时间 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| is_deleted | BOOLEAN | DEFAULT FALSE | 软删除标志 |
| delete_time | DATETIME | NULL | 删除时间 |
**索引:**
```sql
PRIMARY KEY (id),
UNIQUE KEY uk_sid (sid), -- 一名学生只允许一条就业记录
KEY idx_class_id (class_id),
KEY idx_class_deleted (class_id, is_deleted) -- 复合索引,优化班级就业统计
```
**外键:**
```sql
CONSTRAINT fk_employment_student FOREIGN KEY (sid) REFERENCES students(id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_employment_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE RESTRICT ON UPDATE CASCADE
```
---
## 4. 完整 DDL(可直接执行)
```sql
CREATE DATABASE IF NOT EXISTS sms
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE sms;
-- ==================== teachers ====================
CREATE TABLE IF NOT EXISTS teachers (
id INT AUTO_INCREMENT PRIMARY KEY,
num VARCHAR(30) NOT NULL COMMENT '教师编号',
name VARCHAR(30) NOT NULL DEFAULT '' COMMENT '姓名',
age INT NOT NULL DEFAULT 18 COMMENT '年龄',
sex INT NOT NULL DEFAULT 0 COMMENT '性别:0未知 1男 2女',
home_place VARCHAR(50) NULL COMMENT '家乡',
college VARCHAR(50) NULL COMMENT '毕业院校',
specialty VARCHAR(50) NULL COMMENT '专业',
enrollment_time DATETIME NULL COMMENT '入学时间',
graduate_time DATETIME NULL COMMENT '毕业时间',
education VARCHAR(50) NULL COMMENT '学历',
work_experience TEXT NULL COMMENT '工作经验',
coach_area VARCHAR(50) NULL COMMENT '教学方向:应用/项目/算法',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
delete_time DATETIME NULL,
UNIQUE KEY uk_tnum (num),
KEY idx_num (num)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教师表';
-- ==================== classes ====================
CREATE TABLE IF NOT EXISTS classes (
id INT AUTO_INCREMENT PRIMARY KEY,
num VARCHAR(30) NOT NULL COMMENT '班级编号',
name VARCHAR(30) NOT NULL COMMENT '班级名称',
class_start_time DATETIME NULL COMMENT '开课时间',
head_teacher_id INT NULL COMMENT '班主任ID',
coach_teacher_id INT NULL COMMENT '授课老师ID',
tutor_teacher_id INT NULL COMMENT '助教老师ID',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
delete_time DATETIME NULL,
UNIQUE KEY uk_class_num (num),
KEY idx_head_teacher (head_teacher_id),
KEY idx_coach_teacher (coach_teacher_id),
KEY idx_tutor_teacher (tutor_teacher_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='班级表';
ALTER TABLE classes
ADD CONSTRAINT fk_classes_head_teacher FOREIGN KEY (head_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT fk_classes_coach_teacher FOREIGN KEY (coach_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT fk_classes_tutor_teacher FOREIGN KEY (tutor_teacher_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE;
-- ==================== students ====================
CREATE TABLE IF NOT EXISTS students (
id INT AUTO_INCREMENT PRIMARY KEY,
num VARCHAR(30) NOT NULL COMMENT '学生编号',
name VARCHAR(30) NOT NULL DEFAULT '' COMMENT '姓名',
age INT NOT NULL DEFAULT 18 COMMENT '年龄',
sex INT NOT NULL DEFAULT 0 COMMENT '性别:0未知 1男 2女',
home_place VARCHAR(50) NULL COMMENT '家乡',
college VARCHAR(50) NULL COMMENT '毕业院校',
specialty VARCHAR(50) NULL COMMENT '专业',
enrollment_time DATETIME NULL COMMENT '入学时间',
graduate_time DATETIME NULL COMMENT '毕业时间',
education VARCHAR(50) NULL COMMENT '学历',
class_id INT NOT NULL DEFAULT 0 COMMENT '所属班级ID',
advisor_id INT NULL COMMENT '顾问老师ID',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
delete_time DATETIME NULL,
UNIQUE KEY uk_snum (num),
KEY idx_class_id (class_id),
KEY idx_advisor_id (advisor_id),
KEY idx_class_deleted (class_id, is_deleted)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
ALTER TABLE students
ADD CONSTRAINT fk_students_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE RESTRICT ON UPDATE CASCADE,
ADD CONSTRAINT fk_students_advisor FOREIGN KEY (advisor_id) REFERENCES teachers(id) ON DELETE SET NULL ON UPDATE CASCADE;
-- ==================== scores ====================
CREATE TABLE IF NOT EXISTS scores (
id INT AUTO_INCREMENT PRIMARY KEY,
sid INT NOT NULL COMMENT '学生ID',
num VARCHAR(30) NOT NULL COMMENT '考核序次',
score DECIMAL(10,2) NOT NULL COMMENT '分数',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
delete_time DATETIME NULL,
UNIQUE KEY uk_sid_score (sid, num),
KEY idx_sid (sid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成绩表';
ALTER TABLE scores
ADD CONSTRAINT fk_scores_student FOREIGN KEY (sid) REFERENCES students(id) ON DELETE CASCADE ON UPDATE CASCADE;
-- ==================== employment ====================
CREATE TABLE IF NOT EXISTS employment (
id INT AUTO_INCREMENT PRIMARY KEY,
sid INT NOT NULL COMMENT '学生ID',
class_id INT NOT NULL COMMENT '班级ID',
employment_open_time DATETIME NULL COMMENT '就业开放时间',
offer_recived_time DATETIME NULL COMMENT 'Offer下发时间',
employment_company VARCHAR(50) NULL COMMENT '就业公司',
employment_salary DECIMAL(20,5) NULL COMMENT '就业薪资(月薪)',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
delete_time DATETIME NULL,
UNIQUE KEY uk_sid (sid),
KEY idx_class_id (class_id),
KEY idx_class_deleted (class_id, is_deleted)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='就业表';
ALTER TABLE employment
ADD CONSTRAINT fk_employment_student FOREIGN KEY (sid) REFERENCES students(id) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT fk_employment_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE RESTRICT ON UPDATE CASCADE;
```
---
## 5. 索引设计说明
| 表 | 索引名 | 类型 | 字段 | 优化场景 |
|----|--------|------|------|----------|
| students | uk_snum | 唯一 | num | 按学号精确查询 |
| students | idx_class_id | 普通 | class_id | 按班级查学生列表 |
| students | idx_advisor_id | 普通 | advisor_id | 按顾问查学生 |
| students | idx_class_deleted | 联合 | (class_id, is_deleted) | 查某班未删除学生(覆盖常见过滤) |
| classes | uk_class_num | 唯一 | num | 按班级编号精确查询 |
| classes | idx_head_teacher | 普通 | head_teacher_id | 按班主任查班级 |
| scores | uk_sid_score | 唯一 | (sid, num) | 防止重复录入,加速组合查询 |
| scores | idx_sid | 普通 | sid | 按学生查成绩 |
| employment | uk_sid | 唯一 | sid | 保证一人一条就业记录 |
| employment | idx_class_id | 普通 | class_id | 按班级统计就业 |
| employment | idx_class_deleted | 联合 | (class_id, is_deleted) | 班级就业统计过滤已删除记录 |
---
## 6. 数据字典表(V2.0 规划)
```sql
CREATE TABLE IF NOT EXISTS dict_items (
id INT AUTO_INCREMENT PRIMARY KEY,
dict_type VARCHAR(50) NOT NULL COMMENT '字典类型:sex, education, college, specialty, coach_area',
dict_code VARCHAR(50) NOT NULL COMMENT '字典编码,业务表存储的值',
dict_label VARCHAR(100) NOT NULL COMMENT '显示名称',
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序权重',
is_enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
delete_time DATETIME NULL,
UNIQUE KEY uk_type_code (dict_type, dict_code),
KEY idx_type (dict_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通用字典表';
-- 初始数据
INSERT INTO dict_items (dict_type, dict_code, dict_label, sort_order) VALUES
('sex', '0', '未知', 1),
('sex', '1', '男', 2),
('sex', '2', '女', 3),
('education','bachelor', '本科', 1),
('education','master', '硕士', 2),
('education','phd', '博士', 3),
('coach_area','app', '应用', 1),
('coach_area','project', '项目', 2),
('coach_area','algorithm','算法', 3);
```
**引用方式(应用层 JOIN):**
```sql
-- 查询学生时关联字典获取可读名称
SELECT s.*,
d_sex.dict_label AS sex_label,
d_edu.dict_label AS education_label
FROM students s
LEFT JOIN dict_items d_sex ON d_sex.dict_type='sex' AND d_sex.dict_code=CAST(s.sex AS CHAR)
LEFT JOIN dict_items d_edu ON d_edu.dict_type='education' AND d_edu.dict_code=s.education
WHERE s.is_deleted=0;
```
---
## 7. 历史数据归档策略(V3.0 规划)
当数据量达到千万级时,考虑以下归档方案:
| 策略 | 适用场景 | 说明 |
|------|----------|------|
| 分区表(PARTITION BY RANGE) | 按年份归档 | 对 `create_time` 做范围分区,老分区可迁移至冷存储 |
| 归档表(_history 后缀) | 毕业生数据 | 将已毕业学生的成绩/就业记录移入 `students_history` 等归档表 |
| 分库分表 | 超大规模 | 按 `class_id` 哈希分片,需引入 ShardingSphere 或应用层分片 |
**归档判断条件:**
- 学生 `graduate_time` 距今超过 2 年
- 或主动标记为"已归档"状态