
1) 【一句话结论】:教育系统数据库设计需针对亿级成绩表,结合学生表(千万级)、课程表(百万级)的分库分表,采用自然键主键、覆盖索引、按学生ID分片成绩表(水平分片),按班级/课程类型分片学生表和课程表(垂直分库或水平分片),并引入物化视图预聚合与分布式事务,解决高并发与查询性能问题。
2) 【原理/概念讲解】:
主键设计:自然键(学号+课程ID)比自增ID更合理,自增ID全局唯一但分片后数据不均,导致数据倾斜。例如,自增ID分片后,部分分片数据量远大于其他分片,查询时需全表扫描。
索引:B+树结构,覆盖索引(包含查询所需所有字段)减少I/O。如成绩表索引(student_id, course_id, score),查询时直接返回结果,无需回表。
分库分表:水平分片(按学生ID分片成绩表),因为成绩表与学生强关联,按学生ID分片可减少跨表查询;学生表按班级分片(水平分片),课程表按课程类型分片(水平分片),降低单表数据量。
预聚合:通过物化视图定期计算聚合结果(如按学生ID聚合成绩),减少实时查询的I/O。例如,物化视图存储每个学生的成绩总和、平均分,查询时直接读取物化视图。
分布式事务:两阶段提交(强一致性,适用于核心数据)或最终一致性(适用于非核心数据),确保分库分表后数据一致性。
3) 【对比与适用场景】:
| 方式 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 垂直分库 | 按业务表拆库,如学生、成绩分库 | 每库表少,查询快(单表小) | 业务表多,单表数据量不大(如学生表千万级,但单表小) | 跨库查询复杂,需分布式事务 |
| 水平分片 | 按数据量拆表,如成绩表按学生ID分片 | 单表数据量减少,分片键选择关键 | 单表数据量极大(如成绩表亿级) | 分片键选择影响负载,跨分片查询复杂(需预聚合或分片键关联) |
| 跨表查询优化 | 分库分表后跨表查询策略 | 预聚合(物化视图)、分片键关联 | 分库分表后关联多表查询 | 需预计算或路由,避免全表扫描 |
4) 【示例】:
学生表(student):id(主键,自增),student_id(学号,唯一),name,class_id(班级ID,分片键),create_time
分库分表:按class_id水平分片(如class_id mod N,N为分片数),每个分片存储部分班级的学生数据。
课程表(course):id(主键,自增),course_id(课程ID,唯一),course_name,teacher_id,type_id(课程类型,分片键),create_time
分库分表:按type_id水平分片(如type_id mod M,M为分片数),每个分片存储部分课程类型的数据。
成绩表(grade):student_id(外键,关联student.student_id),course_id(外键,关联course.course_id),score,submit_time,主键(student_id, course_id),索引:student_id, course_id(覆盖索引,包含score)
分库分表:按student_id水平分片(如student_id mod P,P为分片数),每个分片存储部分学生的成绩数据。
预聚合示例:创建物化视图(如mv_grade_agg),定期(如每小时)计算每个学生(student_id)的成绩总和、平均分,存储在集中式库或对应分片,查询时直接读取物化视图。
5) 【面试口播版答案】:
面试官您好,针对教育系统数据量,核心是成绩表(亿级)的优化。首先,表结构设计:成绩表主键用学号+课程ID(复合键),避免自增ID分片不均。然后,索引:为成绩表建立覆盖索引(包含student_id, course_id, score),减少I/O。分库分表:成绩表按学生ID水平分片(分片键是student_id mod 分片数),因为学生表关联紧密,分片后每个分片存储部分学生成绩,负载均衡。学生表按班级分片(分片键class_id),课程表按课程类型分片(分片键type_id),减少单表数据量。分库分表后,查询优化:对于单学生多课程查询,用覆盖索引直接返回;跨分片查询(如统计所有学生平均分)用预聚合(物化视图),减少实时查询的I/O。跨表查询(如关联课程表)通过分片键(学生ID)路由到对应分片,关联课程表时,课程表按课程类型分片,确保查询效率。总结:通过主键优化、索引覆盖、分库分表(按学生ID/班级/课程类型分片),并引入物化视图预聚合,解决亿级成绩表的高并发与查询性能问题。
6) 【追问清单】:
7) 【常见坑/雷区】: