简介:悉尼大学Database Management System课程学习资料包,适合数据库初学者和计算机相关专业学生,用于系统掌握数据库管理系统核心原理。内容涵盖数据模型、关系代数、SQL查询、事务处理、并发控制、数据库设计及安全性等知识点,并配有每周教程与作业答案。包体共65个文件,以PDF讲义与习题解答为主,另含SQL脚本、PPT课件及少量压缩包,总大小17.04MB,按week1至week13组织,定位清晰。已有191人学习下载。每周专题均配有练习题和参考解法,例如关系代数、复杂SQL、事务处理、查询优化、存储索引等;同时提供大学模式建表SQL、示例数据及期末复习资料,有助于巩固理论与实践,提升数据库设计与应用能力。
1. 悉尼大学 Database Management System 课程:一门把“库表设计”变成硬功夫的必修课
选这门课之前,很多人以为它只是“教你怎么写 SQL”。上过两个星期才发现,课程真正的重心是数据库管理系统背后的设计逻辑:你凭什么这样建表、为什么这个查询慢、范式化到第几步才算合格。它面向两类人——以后要做后端开发、数据分析的学生,以及想把数据库从“会 CRUD”往上抬一个台阶的从业者。课程把数据建模、关系代数、SQL、事务和索引串成一条线,学完以后至少能回答“这张表设计得烂不烂”和“这条慢查询卡在哪”。你不用把它当纯理论课:每一章节几乎都对应一套能直接在 PostgreSQL 或 MySQL 里复现的练习,跟着走完,收获比背概念大得多。
2. 课程主线与三张必须吃透的图:ER 模型、关系模式与依赖关系
悉尼大学 Database Management System 课程的推进节奏,业界不少数据库入门课也照这个走:先让你学会“把现实世界翻译成表结构”,然后才是 SQL 操纵。第一个里程碑是 ER 图,第二个是关系模式,第三个是函数依赖与范式。三个环节环环相扣,跳过任何一个,后面的作业都会还回来。
2.1 ER 图阶段:实体、联系和基数的一对多陷阱
ER 图阶段要交付的不是“画得好看”,而是“能让人照着建表”。常见作业是给一段业务描述,比如“一个学生可以选多门课,一门课有多个学生选修;每个老师只能带一个班级”,让你画出实体、属性和联系。这个阶段最容易翻车的点是联系上的基数约束:一对多还是多对多,直接决定后续外键放在哪张表。
判定方法其实很机械:先找名词(实体),再找动词(联系),最后检查每一对实体之间的“每”字。出现“每个 A 可以对应多个 B,而每个 B 只能对应一个 A”,就是一对多,外键放 B 侧。出现“一个 A 对应多个 B,一个 B 也对应多个 A”,就是多对多,必须拆出一张中间表,中间表的主键通常是两个外键的组合。
画完 ER 图后,课程一般会要求你用专属的图形标记法(常见的是 crow's foot 或 UML 风格)标注参与约束。这里有个血泪经验:多对多联系里如果联系本身带属性(比如“选课”这个联系带“成绩”属性),这个属性不能挂在任何一端的实体上,只能放在中间表里。否则后面转关系模式时会发现属性无处安放。
2.2 从 ER 图转关系模式:外键位置与命名规范
ER 图到关系模式的转换有固定套路,课程通常要求按“实体成表、属性成列、联系定外键”的步骤来写。一对多联系中,外键加在“多”的那一侧实体表;多对多联系则新建一张关联表,表中只放两个外键加联系自身的属性;一对一联系一般把外键放在任意一侧,但更常见的是合并成一张表。
转换结果要用统一格式呈现,常见交作业格式是这样的表格:
| 关系模式名 | 属性(主键加下划线) | 外键 | 参照表 |
|---|---|---|---|
| Student | student_id, name, email, advisor_id | advisor_id | Faculty |
| Faculty | faculty_id, name, dept | 无 | 无 |
| Enrolment | student_id, course_id, grade | student_id, course_id | Student, Course |
注意主键要加下划线或直接标注 PK,外键要写明参照哪张表。这个阶段我一般会顺手做一件事:把每个关系的属性清单打印出来,人工走一遍“这个属性不再依赖主键吗”的检查。虽然范式化的正式检查在后面,但这时候先扫一遍能省掉后面一大半返工。
2.3 函数依赖:比范式定义更值得手推的关系
函数依赖是这门课里最像“数学题”的部分,也是作业里区分度最高的考点。给定一张表的关系实例,要求你写出其中的函数依赖,或者反过来,给定函数依赖集合让你判断候选键。这两个题型本质是一个能力:看出“哪些列决定哪些列”。
写法上,X → Y 表示“X 的值唯一确定 Y 的值”。判断候选键时,先找出所有只出现在箭头左侧(或没出现)的属性,它们一定在候选键里;然后用函数依赖闭包计算看它能不能推出全属性。闭包算法虽然简单,但手算特别容易漏依赖,尤其是传递依赖 X → Y, Y → Z 这种链条。
我常用的验证方式是把每条依赖倒回数据表里检查:手动找两行,看 X 相同而 Y 不同的情况是否存在。只要存在,这条依赖就不成立。这个方法看着笨,但比空想靠谱得多。课程作业里不少“判断下列函数依赖是否成立”的题目,用这个方法基本不会错。
3. 用 SQL 完成课程作业里的三类必考任务:查询、聚合与多表连接
SQL 部分在悉尼大学 Database Management System 课程里占了整整一个阶段,作业往往要求你在一套预置的数据库上完成一系列查询。虽然不同年份的题目和数据不同,但考点非常固定:基础过滤、多表连接、分组聚合和子查询。下面用一套最小的学生选课库演示这三类必考任务,这套 SQL 在 MySQL 8.x 和 PostgreSQL 上都能直接跑。
先建一张选课表:
-- 选课表:学生与课程的关联,带成绩 CREATE TABLE enrolment ( student_id INT NOT NULL, course_id INT NOT NULL, grade DECIMAL(3,1), semester VARCHAR(10), PRIMARY KEY (student_id, course_id), FOREIGN KEY (student_id) REFERENCES student(student_id), FOREIGN KEY (course_id) REFERENCES course(course_id) );这个建表语句包含了三个课程作业里反复考的要点:复合主键、外键约束、以及NOT NULL的合理使用。grade没有加NOT NULL,因为“还没出成绩”是真值,不能用 0 或者 NULL 以外的东西代替。复合主键(student_id, course_id)直接对应 ER 阶段多对多联系的中间表设计,这是连接知识点的关键位置。
第一类必考任务是带条件的过滤,常见写法是 WHERE 加 AND/OR 组合:
-- 查 2024 Semester 2 成绩不低于 70 分的选课记录,按成绩降序 SELECT student_id, course_id, grade FROM enrolment WHERE semester = '2024 S2' AND grade >= 70 ORDER BY grade DESC;这里有个新手常犯的错误:把ORDER BY放在WHERE前面。SQL 的执行顺序其实是 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY,ORDER BY永远在最后,但它写在查询语句的末尾。记住执行顺序而不是书写顺序,能避免很多玄学报错。
第二类必考任务是聚合,常配合 GROUP BY 统计人数、平均分、最高最低:
-- 每门课的平均分与选课人数,只显示选课人数超过 2 的课程 SELECT course_id, COUNT(*) AS cnt, ROUND(AVG(grade), 1) AS avg_grade FROM enrolment WHERE grade IS NOT NULL GROUP BY course_id HAVING COUNT(*) > 2 ORDER BY avg_grade DESC;这段代码展示了WHERE和HAVING的本质差别:WHERE在分组前过滤行,HAVING在分组后过滤组。AVG(grade)会自动忽略 NULL,但COUNT(*)会数所有行,如果只想数有成绩的,要写COUNT(grade)。这些细节课程作业里都是扣分点,多写一句注释能帮阅卷人看出你懂。
第三类必考是连接查询,常见的是内连接查“学生-选课-课程”三张表:
-- 查学生姓名、课程名与成绩(只显示已选课学生) SELECT s.student_name, c.course_name, e.grade FROM student AS s JOIN enrolment AS e ON s.student_id = e.student_id JOIN course AS c ON e.course_id = c.course_id WHERE e.semester = '2024 S2';连接顺序不是随便写的:先 JOIN 两张小表缩减中间结果集,再 JOIN 第三张,比把大表放前面快得多。另一个常见坑是忘了加WHERE过滤就 JOIN 三张表,造成笛卡尔积膨胀。自连接、左连接和子查询在作业里也常见,尤其是“查没有选任何课的学生”这类题,用LEFT JOIN ... WHERE ... IS NULL比用NOT IN更不容易踩 NULL 的坑。
4. 范式化到 BCNF:一个订单表的分解全过程
范式化是悉尼大学 Database Management System 课程里理论性最强、也最让新手头疼的部分。考试和作业里常见的题型是:给定一个表结构和函数依赖集合,判断它属于第几范式,如果不满足 BCNF 就做分解。难点不在定义本身,而在“怎么拆得干净又不丢依赖”。
4.1 从 1NF 到 BCNF:四条判断标准的速查逻辑
判断范式有一套固定的检查顺序,按层级往上推:
| 范式 | 检查标准 | 违反时的典型症状 |
|---|---|---|
| 1NF | 所有属性都是原子值,不出现多值或重复组 | 一个字段里存多个值(逗号分隔、JSON 数组) |
| 2NF | 在 1NF 基础上,所有非主属性完全依赖主键(无部分依赖) | 复合主键下,某个非主属性只依赖主键的一部分 |
| 3NF | 在 2NF 基础上,无传递依赖(非主属性不依赖其他非主属性) | 某列依赖另一列而不是主键 |
| BCNF | 每个函数依赖 X → Y 的 X 都包含候选键 | 判定更严格,3NF 也拦不住某些异常 |
检查时按“先看主键是不是复合的,再看非主属性之间有没有依赖链”的顺序走,比逐条背定义快。作业里经常给一张“订单明细表”让你判断:它有订单号、订单日期、客户名、商品名、单价、数量。主键是 (订单号, 商品名),但订单日期和客户名只依赖订单号,这就是部分依赖,2NF 都没到。
4.2 订单表到 BCNF 的两步分解示例
用上面订单明细表做完整分解。假设初始表和函数依赖如下:
订单明细(订单号, 下单日期, 客户名, 商品名, 单价, 数量) 函数依赖: 订单号 → 下单日期, 客户名 商品名 → 单价 (订单号, 商品名) → 数量主键是 (订单号, 商品名)。非主属性“下单日期”和“客户名”只依赖订单号(主键的一部分),存在部分依赖,所以需要先拆 2NF。把部分依赖的属性拆出去:
-- 订单头表:以订单号为主键 CREATE TABLE orders ( order_id INT PRIMARY KEY, order_date DATE NOT NULL, customer VARCHAR(50) NOT NULL ); -- 订单明细表:只留下订单号、商品名和数量 CREATE TABLE order_items ( order_id INT NOT NULL, product VARCHAR(50) NOT NULL, quantity INT NOT NULL, PRIMARY KEY (order_id, product), FOREIGN KEY (order_id) REFERENCES orders(order_id) ); -- 商品表:商品名带单价 CREATE TABLE product ( product VARCHAR(50) PRIMARY KEY, price DECIMAL(8,2) NOT NULL );这个拆分动作对应课程里说的“投影分解法”:把违反范式的函数依赖单独成表,原表只保留主键和外键。拆分到这一步,原表已经满足 3NF,但要到 BCNF 还得再检查:3NF 允许“商品名 → 单价”这样依赖键以外属性的依赖存在吗?允许,但 BCNF 不允许,因为商品名不是候选键。所以还需要把商品拆出去——上面代码里已经完成了这一步。
4.3 分解无损的判断:公用属性与依赖保留
分解完最怕的是丢了函数依赖或者分解不可逆。课程里教了两个判定方法:无损连接判定看两个分解后的表是否有至少一个共同属性,并且该属性在其中一张表是主键;依赖保留则看每个函数依赖是否都能在某一张分解后的表里直接验证。上面三次分解都满足这两个条件:orders 和 order_items 通过 order_id 连接,order_items 和 product 通过 product 连接,每条函数依赖都能在对应表里用主键唯一性直接确认。
实际做作业时,我的习惯是把每个分解后的表在草稿上重写一遍函数依赖,逐条划勾。只要有一条依赖在两个表里都找不到位置,说明分解丢依赖了,这种答案在考试里扣分非常狠。特别注意:BCNF 分解有时会破坏依赖保留,出现这种情况时要不要退而求其次用 3NF,是课程里值得跟老师讨论的经典取舍。
5. 数据库课程作业常见的 5 个翻车现场:现象、原因与解法
作业写得再顺,跑数据时总有几个反复出现的坑。下面五条是按出现频率排的,每一条都是我见过的真实翻车记录。
5.1 外键约束插入失败:明明有数据,却说不满足完整性
现象:向从表插入记录时,报外键约束错误,但去主表查,参照的那行明明存在。
原因:最常见的是数据字符集不一致。主表和从表的连接列一个用了 utf8mb4,一个用了 latin1 或 utf8,看起来内容一样,但二进制比较不相等。其次是从表连接列的数据类型与主表主键不一致,比如一个是 INT,一个是 VARCHAR(11),MySQL 在做隐式转换时走了不同的索引路径。
解决:统一字符集和排序规则;连接列类型严格对齐主键类型。建议在初始化表的时候,把CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci统一写到库级配置,而不是每张表各写各的。排错时先执行SHOW CREATE TABLE检查两边定义,再比对列类型,基本两步定位。
5.2 聚合查询结果看着对,一验算全是错的:GROUP BY 的隐式分组踩坑
现象:执行SELECT student_id, course_id, COUNT(*) FROM enrolment没写 GROUP BY,MySQL 低版本能跑出一行结果,但结果毫无意义。
原因:MySQL 5.7 之前默认关闭了ONLY_FULL_GROUP_BY模式,允许 select 列表里出现既不参与分组也不在聚合函数里的列,取的是随机行的值。6.0 以后默认开启,但很多教学环境用的老镜像还是旧行为。
解决:把sql_mode里加上ONLY_FULL_GROUP_BY,一劳永逸;写查询时养成“SELECT 里出现的每个非聚合列,都必须出现在 GROUP BY 里”的习惯。这条规则比背任何 SQL 文档都管用,能避免 90% 的聚合踩坑。
5.3 字符集乱码:中文注释和表数据全变问号
现象:插入中文后查询显示??,或者建表时注释里的中文直接变乱码。
原因:连接层未指定字符集。数据库表是 utf8mb4,但客户端连接用的还是 latin1,字符在传输过程中被转坏。课程作业里因为是本机测试环境,很多人不会刻意设连接字符集,一提交代码给多人协作库就暴露了。
解决:每次建立连接后立刻执行SET NAMES utf8mb4;,或者把 JDBC 连接串加上characterEncoding=utf8mb4。建库时用DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci,避免每张表单独声明时写错。
5.4 无法确定后端是什么数据库:SQL 方言带来的工具失灵
现象:用一个通用数据库工具或导入脚本批量执行 SQL,工具提示类似“was not able to fingerprint the back-end database management system”的信息,或者某个查询在一个库里能跑,在另一个库里直接语法报错。
原因:不同数据库管理系统的 SQL 方言有差异。MySQL 用反引号包裹表名,PostgreSQL 用双引号;LIMIT 语法两者都支持,但分页参数写法不同;字符串连接 MySQL 用CONCAT,SQL Server 用+。自动识别工具如果拿到一段带强烈方言特征的 DDL 或查询,就可能无法确认后端数据库类型而拒绝执行。
解决:课程作业如果是指定数据库环境,先确认目标管理系统版本;如果是写一份通用脚本,尽量用 ANSI SQL 标准语法,避免反引号和方言函数。遇到工具报“无法识别后端数据库管理系统”时,先把脚本里最有方言特色的语句(比如AUTO_INCREMENT、反引号)换成标准写法再试,通常就能通过。查表操作尽量走INFORMATION_SCHEMA,不同数据库都有兼容接口,比直接查询系统表更稳。
5.5 删除父表数据时外键冲突:忘了 ON DELETE 的行为
现象:删除一条课程记录时,报外键约束错误,明明子表已经没有相关记录,但删除仍然失败。
原因:外键约束的默认行为是ON DELETE RESTRICT,只要子表历史上存在过记录(即便已删除),某些数据库在检查时依然报冲突;或者你记得清过子表数据,但用的删除语句没有提交事务,另一个会话还持有行锁。
解决:确认删除目标前先执行SELECT COUNT(*) FROM enrolment WHERE course_id = 该课程ID;如果确认无引用,检查事务是否提交。在创建外键时明确写ON DELETE CASCADE或SET NULL而不是靠默认值,行为就可预期了。
6. 用 EXPLAIN 和 INFORMATION_SCHEMA 验证作业设计:让数据库自己回答“设计得怎样”
最后一个环节不是加新功能,而是验证你已经做完的库表设计和查询是否合理。课程作业提交前,如果能把下面这套验证流程跑一遍,设计问题基本都能暴露。
先看查询计划。对作业里每个核心查询执行EXPLAIN SELECT ...,检查输出里的type列。出现ALL表示全表扫描,对超过几千行的表来说就是慢查询的预警;出现index或者ref表示走了索引,基本合格。重点看连接顺序和是否用到覆盖索引:把常用查询里的所有列都放进同一个复合索引,可以让Extra列出现Using index,意思是查询不用回表,这在作业答辩里是加分项。
再看表结构信息。用 INFORMATION_SCHEMA 核对设计一致性:
-- 检查所有表的字符集,避免出现混用 SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema = '你的数据库名'; -- 检查外键关系是否完整建立 SELECT table_name, constraint_name, referenced_table_name FROM information_schema.referential_constraints WHERE constraint_schema = '你的数据库名';这两条查询能快速发现两张最常见的低级错误:表与表之间字符集不统一,以及外键漏建。前者会导致查询慢和莫名其妙的连接失败,后者则直接违背 ER 阶段的设计意图。建议把这两条查询固定存成一个小脚本,每次作业提交前跑一遍。
我的习惯是:所有主键和外键列都起表名_id的命名格式,建表时顺手把字符集写进建表语句而不是依赖库默认值,每次写完查询都跑一次 EXPLAIN 看有没有全表扫描。这套流程看着朴素,但确实帮我挡掉了不少交作业前才发现的设计问题。这门课真正的收获不是记住范式定义,而是学会让数据库管理系统用执行计划这类客观输出告诉你设计哪里不对——希望帮到你。
本文还有配套的精品资源,点击获取