51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

在好未来系统中,需要存储学生、课程、成绩、作业提交等数据,其中“学生-课程-成绩”关联表需要支持快速查询(如按学生ID查询所有课程成绩)、实时更新(成绩提交后立即同步)。请设计该表的数据库结构,并说明索引策略、分库分表策略(若适用),以及如何优化查询性能。

好未来Java难度:中等

答案

1) 【一句话结论】采用以(学生ID, 课程ID)为复合主键的成绩关联表,通过覆盖索引加速查询,按学生ID水平分库分表分散数据,结合事务与乐观锁保障实时更新与并发一致性。

2) 【原理/概念讲解】首先,学生与课程是多对多关系,需中间表关联。核心设计是复合主键:student_id和course_id共同构成主键,既保证数据唯一性,又为“按学生ID查询所有课程成绩”提供高效索引(B+树索引天然支持范围查询)。索引策略上,除主键复合索引外,需为student_id、course_id分别建单列索引,以及包含score的复合覆盖索引(如student_id, course_id, score),实现“索引覆盖”,避免回表操作。实时更新方面,通过数据库事务(ACID)保证成绩提交后立即同步,同时引入乐观锁(如version字段)处理并发提交,防止数据冲突。分库分表策略:若数据量超百万级,按student_id的hash取模到不同分表(如student_id % 32),分散数据量,提升查询性能;跨分库查询通过分片路由框架(如ShardingSphere)统一管理。

类比:成绩关联表像“成绩登记簿”,主键是“学生+课程”的组合(类似簿的页码),按学生和课程快速定位成绩;索引则像簿上的索引页,覆盖查询所需字段(如成绩),直接获取结果,无需翻页(回表)。

3) 【对比与适用场景】

策略类型定义特性使用场景注意点
垂直分库按业务拆分表(如成绩表单独库)单表数据量小,查询复杂度低业务表关联少,单表数据量大需跨库查询,性能依赖网络
水平分表(按学生ID)按student_id哈希取模分表单表数据量可控,查询局部性高学生数多,课程数相对稳定跨分表查询需路由,写入分散

4) 【示例】
表结构设计(MySQL示例):

CREATE TABLE student_course_score (
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    score DECIMAL(5,2) NOT NULL,
    submit_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    version INT NOT NULL DEFAULT 0, -- 乐观锁版本号
    PRIMARY KEY (student_id, course_id),
    INDEX idx_student (student_id),
    INDEX idx_course (course_id),
    INDEX idx_student_course (student_id, course_id, score) -- 覆盖索引
);

分库分表示例(假设分片数32):

-- 分表规则:student_id % 32 决定分表
CREATE TABLE student_course_score_0 (
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    score DECIMAL(5,2) NOT NULL,
    submit_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    version INT NOT NULL DEFAULT 0,
    PRIMARY KEY (student_id, course_id),
    INDEX idx_student (student_id),
    INDEX idx_course (course_id),
    INDEX idx_student_course (student_id, course_id, score)
) ENGINE=InnoDB;
...
CREATE TABLE student_course_score_31 (
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    score DECIMAL(5,2) NOT NULL,
    submit_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    version INT NOT NULL DEFAULT 0,
    PRIMARY KEY (student_id, course_id),
    INDEX idx_student (student_id),
    INDEX idx_course (course_id),
    INDEX idx_student_course (student_id, course_id, score)
) ENGINE=InnoDB;

5) 【面试口播版答案】
“面试官您好,针对学生-课程-成绩的关联表设计,核心思路是构建一个以(学生ID, 课程ID)为复合主键的中间表,这样既保证数据唯一性,又为快速查询提供索引基础。首先,表结构上,包含student_id、course_id、score等字段,主键设为这两个字段,因为查询时经常按学生ID筛选所有课程成绩,复合主键能直接定位到记录。索引策略上,除了主键索引,还会为student_id和course_id分别建单列索引,以及包含score的复合覆盖索引(如student_id, course_id, score),这样查询时可以直接从索引中获取结果,避免回表。关于实时更新,通过数据库事务(如BEGIN TRANSACTION...COMMIT)保证成绩提交后立即同步,同时引入乐观锁(version字段)处理并发提交,防止数据冲突。分库分表方面,假设数据量较大(比如百万级学生课程记录),会按student_id的hash取模到不同分表(如student_id % 32),分散数据量,提升查询性能。总结来说,这个设计通过复合主键+覆盖索引实现快速查询,事务+乐观锁保障实时更新与并发一致性,分库分表应对数据量增长。”

6) 【追问清单】

  • 问题:分库分表后,如何处理跨分库的查询(如按课程ID统计所有学生成绩)?
    回答:通过分片路由框架(如ShardingSphere)统一管理跨分库查询,将请求路由到对应分片,或按课程ID分库,将跨分库查询转为同库查询。
  • 问题:乐观锁在并发场景下的性能影响?
    回答:乐观锁通过版本号比较,若冲突重试,在高并发下需考虑重试策略(如指数退避),但比悲观锁更轻量,适合读多写少的场景。
  • 问题:索引选择是否考虑了写入性能?
    回答:B+树索引写入性能较好,高并发下通过分库分表分散写入压力,避免单点瓶颈;同时覆盖索引减少回表,提升查询性能。

7) 【常见坑/雷区】

  • 主键设计错误:若主键不是(student_id, course_id),会导致数据重复或查询效率低。
  • 索引覆盖不足:未为查询字段建覆盖索引,导致回表,影响性能。
  • 分库分表策略不当:按学生ID分库后,查询按课程ID统计时需跨库,性能差。
  • 实时更新未考虑事务:导致数据不一致(如成绩提交后未同步)。
  • 忽略乐观锁:高并发下未处理并发提交冲突,可能导致数据丢失或脏读。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1