27、查询所有学生的选课情况
下面是几种更高效、更规范的写法以及性能优化的思路。一、原 SQL 的问题分析select Student.s_no, Student.sname, Course.cname from Student, Sc, Course where Student.s_no Sc.s_no and Sc.c_no Course.c_no;这是隐式内连接等价于INNER JOIN只能查到 “选了课的学生”没选课的学生不会出现在结果里。老写法可读性差优化器在复杂场景下可能不如显式 JOIN 写法稳定。二、需求澄清题目是 “查询所有学生的选课情况”这里有两种理解只看选了课的学生原 SQL 的逻辑所有学生都要出现没选课的课程名显示 NULL更常见的 “所有情况” 理解下面分别给出高性能写法。三、写法 1等价于原 SQL只查有选课记录的学生写法 1-1显式 INNER JOIN可读性更好性能无差别sqlSELECT s.s_no, s.sname, c.cname FROM Student s INNER JOIN Sc sc ON s.s_no sc.s_no INNER JOIN Course c ON sc.c_no c.c_no;用别名s/sc/c减少重复书写更简洁。优化器处理逻辑和原 SQL 一致但可读性更强维护更方便。四、写法 2真正 “所有学生” 的写法含未选课的学生用LEFT JOIN保证所有学生都出现没选课的课程名显示NULL。写法 2-1标准 LEFT JOIN 写法推荐sqlSELECT s.s_no, s.sname, c.cname FROM Student s LEFT JOIN Sc sc ON s.s_no sc.s_no LEFT JOIN Course c ON sc.c_no c.c_no;无论学生有没有选课都会出现在结果里没选课的行cname为NULL。性能上只要关联字段有索引和内连接差别不大。五、性能优化关键核心想让这个查询跑得更快比换写法更重要的是索引优化必须创建的索引sql-- 学生表主键一般已建 ALTER TABLE Student ADD PRIMARY KEY (s_no); -- 选课表索引联合索引最优 CREATE INDEX idx_sc_sno_cno ON Sc(s_no, c_no); -- 课程表主键一般已建 ALTER TABLE Course ADD PRIMARY KEY (c_no);索引为什么关键Student.s_no和Sc.s_no关联索引能快速定位学生的选课记录。Sc.c_no和Course.c_no关联索引能快速匹配课程名。没有索引时会变成全表扫描数据量大时性能会指数级下降。六、其他高性能变体根据场景选择场景 1只需要统计选课情况不需要课程名如果只是想知道学生选了多少课可以直接聚合减少 JOIN 开销sqlSELECT s.s_no, s.sname, COUNT(sc.c_no) AS course_count FROM Student s LEFT JOIN Sc sc ON s.s_no sc.s_no GROUP BY s.s_no, s.sname;只查学生和选课次数不用关联课程表性能更高。场景 2数据量超大想避免重复数据如果一个学生选多门课会返回多行记录想合并课程名MySQL 8.0 用GROUP_CONCATsqlSELECT s.s_no, s.sname, GROUP_CONCAT(c.cname SEPARATOR , ) AS course_names FROM Student s LEFT JOIN Sc sc ON s.s_no sc.s_no LEFT JOIN Course c ON sc.c_no c.c_no GROUP BY s.s_no, s.sname;只返回每个学生一行课程名用逗号拼接减少结果集行数。