ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

数据库原理实验从GreatSQL环境部署到SQL实操的完整避坑指南

数据库原理实验从GreatSQL环境部署到SQL实操的完整避坑指南

简介:郑州大学计算机与人工智能学院《数据库系统原理》课程的实验报告资源,适合正在学习数据库原理、需要完成同类实验的学生参考。内容涵盖认识DBMS系统、万里数据库GreatSQL的安装与配置、基本表/视图/触发器/存储过程等逻辑组件操作,以及实验报告撰写规范,完整记录了关闭SELinux与防火墙、安装依赖包、解压部署、启动服务等关键步骤,并配有结果截图说明与过程分析。资源为1个docx文档,压缩包约3.69MB,结构清晰便于直接借鉴。目前已累计509人学习,能够帮助读者快速掌握GreatSQL环境搭建方法,规范撰写实验报告,并解决安装配置中常见的权限、端口和依赖问题,适合数据库课程实验备查与技能提升。

1. 为什么数据库原理实验要从“装好一个DBMS”开始

数据库原理实验报告这件事,多数人以为难点在SQL语句,真正动手才发现,最容易被卡住的反而是第一步:把DBMS装好并跑起来。一套常见的实验环境是这样搭的:虚拟机里跑CentOS,用二进制包部署GreatSQL 8.0.32。相比Windows一键安装,这种方式多绕几步,却能逼着你把目录结构、系统服务、配置文件这些平时看不见的东西一次摸清楚。

这篇文章围绕一条完整可复现的实验链路展开:环境配置与部署、建库建表和索引、交互式SQL验证、报告排版与验收答辩。适合正在按“认识DBMS—建库建表—SQL操作”这条主线完成数据库原理实验的同学,也适合想快速把GreatSQL基础环境搭起来、理解数据页与逻辑组件关系的开发者。

2. 环境准备与部署:关闭SELinux和防火墙后用二进制包装好GreatSQL

2.1 为什么选“虚拟机+CentOS+二进制包”而不是一键安装

选型这一步不是随便定的,后面所有实验都依赖这个环境,选错了后面全是坑。第一,用VMware跑虚拟机是为了隔离。实验过程里要改系统安全策略、反复启动停止数据库服务,装在物理机上出了问题会影响日常使用;虚拟机里随便折腾,出问题还可以用快照当后悔药。第二,选CentOS 7以上而不是带图形界面的系统,是为了强迫自己用命令行和systemd管理服务,这套操作习惯跟生产环境一致。第三,也是最重要的一点,用二进制包而不是yum install,是因为yum自动装好后程序文件分散在/usr/bin、/var/lib、/etc这些目录里,你根本看不清一个数据库管理系统由哪些部分组成;二进制包解压后所有组件集中在一个目录下,bin、lib、share一目了然,正好对应实验中“认识DBMS系统构架”这个目标。

2.2 关闭SELinux和防火墙:安全策略与数据库运行的取舍

新装好的CentOS上第一件事不是装数据库,而是先处理SELinux和防火墙,这一点很多同学不理解。SELinux是强制访问控制(MAC)机制,它会限制mysqld进程的文件读写和网络通信权限。数据库启动时要执行大量特权操作,被SELinux拦下后,日志里的报错很玄学——看起来是权限问题,但文件属主和权限明明都是对的。另外SELinux的配置策略复杂,学习和排查成本高;它对每个进程做访问控制检查,还会造成一定的性能开销。防火墙的逻辑类似:数据库监听3306端口,默认防火墙策略会挡掉外部连接,关闭后能避免端口阻塞,也简化了虚拟机的网络配置。这套取舍在答辩时经常被追问,理由是站得住的。

# 临时关闭SELinux,立即生效 setenforce=0 # 持久化关闭:把配置文件里的SELINUX=改为disabled,重启后仍然生效 sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config # 关闭防火墙并禁用开机自启 systemctl stop firewalld systemctl disable firewalld # 验证当前状态,输出Disabled说明已关闭 getenforce

注意setenforce=0只对当前运行周期生效,重启后系统会重新读取配置文件,所以临时和持久化两条命令都要执行。很多同学只跑了第一条,虚拟机一重启又变回Enforcing,这就是后面要讲的经典翻车点。

2.3 部署实操:依赖包、解压、系统用户、systemd与启动验证

依赖包看起来一长串,实际分成几类:libaio-devel是异步IO库,InnoDB写数据时要依赖它;numactl系列用于NUMA架构下绑定CPU和内存,mysqld启动时会检测;jemalloc是高性能内存分配器,用来减少内存碎片;其余perl相关包是数据库初始化脚本的运行依赖。被问到“为什么装这么多包”时,能讲清libaio、numactl、jemalloc这三个就足够说明你真的理解了。

yum install -y pkg-config perl libaio-devel numactl-devel numactl-libs \ net-tools openssl openssl-devel jemalloc jemalloc-devel \ perl-Data-Dumper perl-Digest-MD5 python2 perl-JSON perl-Test-Simple

依赖装完后,把下载好的二进制包放到/usr/local目录下解压,然后创建专用的mysql系统用户。用/sbin/nologin作为登录shell,意思是这个账户只用来跑服务,不允许登录系统,属于标准的服务账户做法。

cd /usr/local tar xf GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal.tar.xz /sbin/groupadd mysql /sbin/useradd -g mysql mysql -d /dev/null -s /sbin/nologin mkdir -p /var/lib/mysql chown -R mysql:mysql /var/lib/mysql /usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal

接下来编辑systemd服务文件,把GreatSQL注册成系统服务。服务文件里最核心的是ExecStart,路径必须和实际解压目录完全一致,很多启动失败都出在这一行。

[Unit] Description=GreatSQL Server After=network.target [Service] User=mysql Group=mysql ExecStart=/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal/bin/mysqld --defaults-file=/etc/my.cnf Restart=on-failure [Install] WantedBy=multi-user.target

然后编辑全局配置文件/etc/my.cnf,这里决定了数据库的数据文件放哪、监听哪个端口、日志写到哪里。datadir对应的就是物理存储位置,后面查看数据库文件时都要回到这个目录。

[mysqld] user=mysql basedir=/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal datadir=/var/lib/mysql socket=/tmp/mysql.sock port=3306 pid-file=/var/lib/mysql/mysqld.pid log-error=/var/log/mysql/error.log character-set-server=utf8mb4

启动验证分三步走。先systemctl daemon-reload让新的服务文件生效,再systemctl start greatsql启动,最后systemctl status greatsql确认状态。进程级别还要用ps -ef | grep mysqld确认mysqld进程存在,ss -lntp | grep mysqld确认3306端口正常监听,ls /var/lib/mysql查看初始化出来的数据文件。如果启动失败,第一件事就是去看log-error指向的错误日志,不要瞎猜。

提示:我这套流程里所有命令都是在root用户下执行的,如果你用普通用户加sudo,注意chown那一步的属主依然是mysql,别顺手把安装目录改成自己的用户名。

3. 数据库设计实验:从逻辑组件到索引的建库建表实务

3.1 认识DBMS逻辑组件与物理存储:基本表、视图、触发器、存储过程、约束

实验一要求了解数据库系统的逻辑组件和物理组件,这部分不是背概念,而是要能在GreatSQL里把这些组件找出来。逻辑组件里,基本表是实际存储数据的表,SHOW TABLES可以直接看到;视图是虚拟表,基于一个或多个基本表的查询结果动态生成,不实际存储数据;触发器是特殊类型的存储过程,在插入、更新、删除事件发生时自动执行,常用于维护数据一致性和业务规则;存储过程是预编译的SQL语句集合,封装后可以反复调用;约束是对数据的限制规则,主要包括主键、外键、唯一和非空。

information_schema是MySQL体系里的元数据库,专门存这些组件的信息,实验报告里常用的查看命令有这么几条。

表1:逻辑组件与information_schema查看命令对照

组件作用查看命令
基本表实际存储数据的表SHOW TABLES;
视图基于查询结果的虚拟表SHOW FULL PROCESSLIST;
触发器事件发生时自动执行SELECT * FROM information_schema.TRIGGERS;
存储过程预编译SQL单元SELECT * FROM information_schema.ROUTINES WHERE ROUTINE_TYPE='PROCEDURE';
约束数据完整性规则SELECT * FROM information_schema.KEY_COLUMN_USAGE;

物理组件方面,GreatSQL的组成包括连接池组件、系统管理和控制工具、SQL接口组件、查询解析器、查询优化器、可插拔存储引擎以及系统与日志文件。物理存储的存储单位是数据页,InnoDB默认页大小16KB,数据以页为单位在磁盘上存放,最终体现为文件。确定数据存放位置的方法就是查看my.cnf里的datadir配置,这个我们在部署阶段已经配过了。

3.2 建库建表:主键、非空约束与复合主键的设计取舍

实验二从创建数据库开始,这一步很简单但后面的表都挂在它下面。

CREATE DATABASE DB; SHOW DATABASES; USE DB;

建表是实验二的核心。教材要求建STUDENTS、COURSES、SC三张表,注意第一次建表时只用了id和name两个字段做练习,真正落地的正式表结构必须带上完整属性。

CREATE TABLE STUDENTS ( Sno char(9) PRIMARY KEY, Sname char(10) NOT NULL, Sex char(2), Birthday DATE, Speciality char(20), Dno char(4) ); CREATE TABLE COURSES ( Cno char(5) PRIMARY KEY, Cname char(20) NOT NULL, Period int, Credit int ); CREATE TABLE SC ( Sno char(9), Cno char(5), Grade int, PRIMARY KEY (Sno, Cno) );

这里几个设计点要能解释清楚。Sno用char(9)定长字符串,因为学号长度固定,定长类型比varchar省存储开销;Sname加NOT NULL,不允许一条没有姓名的学生记录存在,这是非空约束的实际意义;SC表用(Sno, Cno)复合主键,因为一个学生选一门课只产生一条成绩记录,(Sno, Cno)这个组合才能唯一标识一行,单独拿Sno或Cno都不唯一。这个复合主键的设计在答辩时几乎必问,核心答法就是“语义上的唯一性由组合决定”。

插入几条测试数据用于后续查询验证。

INSERT INTO STUDENTS VALUES ('201705001', '张华', '男', '1999-12-16', '计算机', 'CS'), ('201705002', '张晓霞', '女', '1999-01-01', '软件工程', 'SE'), ('201706001', '李玉', '女', '1999-10-17', '数学', 'MA');

删除表时有个容易忽略的问题。STUDENTS、COURSES被SC的外键引用,直接删父表会报外键约束错误,所以要么先删SC再删父表,要么用DROP TABLE students CASCADE。实验环境里用CASCADE省事,但生产环境不建议这么做,正式库删表前一定要先备份。

3.3 索引设计:普通索引与唯一索引的创建、删除和验证

索引是数据库性能的关键,实验二要求用SQL语句创建和删除索引。最典型的案例是在Students表的Dno列上建普通索引,在Courses表的Cno列上建唯一索引。

CREATE INDEX Student_Dept ON Students (Dno); CREATE UNIQUE INDEX Course_Cno ON Courses (Cno); SHOW INDEX FROM Students; DROP INDEX Course_Cno ON Courses;

设计上要注意区别:Dno是经常作为查询条件的列,按院系查学生是很典型的检索场景,普通B+树索引能加速这类查询;而Course_Cno建的是唯一索引,语义是保证Cno列的取值不重复。主键本身会自动创建聚簇索引,所以Cno上其实已经不缺唯一性,再做一次唯一索引,更多是为了验证“主键约束”和“唯一索引”是两个层面的概念——一个是约束,一个是索引结构。实验报告里建议把SHOW INDEX的输出截图留存,用来说明索引创建前后查询计划的差别,后面的交互式SQL实验会用到。

注意:在生产环境的真实业务表里,已经有主键的列通常不需要再单独建唯一索引,这里建只是为了实验验证,别把习惯带到真实项目里。

4. 交互式SQL实验:六张表上完整跑通教材查询与更新案例

4.1 实验数据准备:六张表结构与外键关系

实验三要覆盖教材里的查询和更新案例,原来的三张表不够用,需要扩展成六张表:Departments、Teachers、Students、Courses、SC、Teaches。这六张表构成了一个简化版的教学管理系统,外键关系比实验二复杂得多。建表SQL可以直接复用,但要注意执行顺序——先建不依赖其他表的Departments和Courses,再建引用它们的Teachers、Students,最后建SC和Teaches。

CREATE TABLE Departments ( Dno char(4) PRIMARY KEY, Dname char(20), Dheadno char(7) ); CREATE TABLE Teachers ( Tno char(7) PRIMARY KEY, Tname char(10) NOT NULL, Sex char(2) CHECK (Sex = '男' OR Sex = '女'), Birthday DATE, Title char(10), Dno char(4) ); CREATE TABLE Students ( Sno char(12) PRIMARY KEY, Sname char(20) NOT NULL, Birthday DATE, Speciality char(20), Dno char(4), Sex char(4) ); CREATE TABLE Courses ( Cno char(5) PRIMARY KEY, Cname char(30) NOT NULL, Period SMALLINT, Credit SMALLINT ); CREATE TABLE SC ( Sno char(12), Cno char(5), Grade int CHECK (Grade > 0 AND Grade <= 100), PRIMARY KEY (Sno, Cno), FOREIGN KEY (Sno) REFERENCES Students (Sno), FOREIGN KEY (Cno) REFERENCES Courses (Cno) ); CREATE TABLE Teaches ( Tno char(7), Cno char(5), TCsores int, PRIMARY KEY (Tno, Cno) );

外键关系没有在建表时全部写完,后续用ALTER TABLE补上。这是初学阶段比较友好的做法:建表时先把结构定清楚,再逐个添加外键,能更直观地理解FOREIGN KEY语法和引用关系。

ALTER TABLE teaches ADD FOREIGN KEY (Cno) REFERENCES Courses (Cno); ALTER TABLE teaches ADD FOREIGN KEY (Tno) REFERENCES teachers (Tno); ALTER TABLE students ADD FOREIGN KEY (Dno) REFERENCES departments (Dno); ALTER TABLE teachers ADD FOREIGN KEY (Dno) REFERENCES departments (Dno);

插入数据的顺序也受外键约束影响,必须先插父表再插子表。顺序反了会直接报“外键约束失败”,这不是SQL写错,而是数据依赖顺序的问题。先插departments和courses,然后teachers和students,最后SC和teaches,每张表插完后用SELECT COUNT(*)验证行数。

4.2 查询语句的分类验证:从全表查询到条件、范围与集合匹配

查询是实验三的重头戏,要按类型分类跑,每一类都要截图留痕。第一类是不带WHERE的全表查询,比如SELECT * FROM Courses,用来确认数据完整写入;带计算列的查询也很典型,比如用YEAR函数从Birthday计算年龄,这属于表达式查询。

-- 全表查询 SELECT * FROM Courses; -- 计算列查询:直接算年龄 SELECT Sname, 2024 - YEAR(Birthday) AS Age FROM Students; -- 带WHERE的等值比较 SELECT Tname, Sex FROM Teachers WHERE Title = '讲师'; -- 去重查询:不及格学生的学号,DISTINCT去掉重复 SELECT DISTINCT Sno FROM SC WHERE Grade < 60;

第二类是范围查询,BETWEEN和NOT BETWEEN是一对,注意BETWEEN是闭区间,包含边界值。

-- 查询1997到1999年出生的学生 SELECT Sname, Speciality FROM Students WHERE YEAR(Birthday) BETWEEN 1997 AND 1999; -- NOT BETWEEN是互补范围 SELECT Sname, Speciality FROM Students WHERE YEAR(Birthday) NOT BETWEEN 1997 AND 1999;

第三类是集合匹配IN和NOT IN。IN的语义是“属于这个集合”,注意集合里的字符串也要用单引号。

SELECT Sno, Sname FROM Students WHERE Speciality IN ('计算机', '软件工程'); SELECT Sno, Sname FROM Students WHERE Speciality NOT IN ('计算机', '软件工程');

通常教材这一步还会补一条模糊匹配LIKE和一条排序查询,虽然不是所有同学都会跑到,但实验报告里多覆盖一类查询,验收时内容更完整。

-- 模糊匹配:姓张的学生 SELECT Sname, Sno FROM Students WHERE Sname LIKE '张%'; -- 排序:成绩从高到低 SELECT Sno, Cno, Grade FROM SC ORDER BY Grade DESC;

执行每一条查询后都要观察结果集是否符合预期。比如DISTINCT那条,如果SC表里同一个学号有多条不及格记录,去重后只保留一个;LIKE '张%'只能匹配姓张开头的记录,'%张'匹配结尾是张的记录。实验结果分析就要写这些观察,不能让截图自己说话。

4.3 更新操作与标准SQL的差异:插入、修改、删除的边界条件

更新操作分插入、修改、删除三类。插入就是给现有表补充行,注意外键约束和CHECK约束都会在这里生效,Grade超过100直接报错。修改数据最怕的一件事是UPDATE不带WHERE,整张表的成绩全被改掉,这在真实业务里是事故级别的问题。我一般会先写SELECT把要改的行查出来确认,再执行UPDATE,养成“先查后改”的习惯。

-- 安全更新示范:先查再改 SELECT * FROM SC WHERE Sno = '201705001' AND Cno = 'cs101'; UPDATE SC SET Grade = 90 WHERE Sno = '201705001' AND Cno = 'cs101';

DELETE的边界条件在外键上。被其他表引用的行不能直接删,比如删掉departments里还挂着教师的系,外键约束会拦下来。正确做法是先处理子表数据,或者用事务包裹,确认没问题再COMMIT。事务在GreatSQL里跟标准SQL有一个明显差异:GreatSQL基于MySQL 8.0,默认隔离级别是Repeatable Read,而标准SQL默认是Read Committed;另外UPDATE和DELETE支持LIMIT扩展,这是MySQL系的特有语法。实验报告里可以单独写一段“标准SQL与GreatSQL差异”的对比,这类内容在评分时很加分。

提示:做更新类实验前一定要确认当前会话没有开启自动提交以外的隐式事务,或者干脆主动用BEGIN开启事务,操作完验证结果再COMMIT。这样就算手误也能回滚,等于给自己留了后悔药。

5. 实验报告避坑指南:安装启动、SQL执行与截图排版的五个翻车点

5.1 systemctl启动失败:目录属主与systemd路径不一致

现象:systemctl start greatsql执行后,服务状态一直是activating或failed,ps查不到mysqld进程。

原因:八成是解压后的安装目录属主不是mysql,mysqld没有权限写日志和临时文件;或者systemd服务文件里ExecStart的路径跟实际解压目录不一致。

解决:执行chown -R mysql:mysql把安装目录和/var/lib/mysql全部授权,然后逐字核对greatsql.service里的路径,最后看log-error指向的日志文件,里面的报错信息会直接告诉你是权限问题还是路径问题。

5.2 SELinux改完重启又恢复:临时与持久化配置分不清

现象:刚执行完setenforce=0,getenforce显示Disabled,但虚拟机一重启又变回Enforcing。

原因:setenforce=0只是临时修改当前运行状态,没有写入配置文件,重启后系统读到的还是/etc/selinux/config里的enforcing。

解决:必须修改/etc/selinux/config,把SELINUX=enforcing改成SELINUX=disabled,然后重启或用setenforce=0配合生效。用getenforce验证一次,确认输出是Disabled才算彻底关掉。这条我见过太多同学踩,几乎每届都有。

5.3 中文引号导致SQL报错:全角字符与字符集问题

现象:执行WHERE Title='讲师'时报语法错误,或者插入的中文数据在查询结果里显示成乱码。

原因:SQL字符串常量里混入了中文全角引号“ ”或‘ ’,数据库解析器不认全角字符;另一种情况是表或库的字符集不是utf8系列,中文落盘后编码不对。

解决:所有SQL里的字符串常量一律用英文半角单引号,写完后可以用编辑器开启“显示全角字符”高亮检查;建表时显式指定DEFAULT CHARSET=utf8mb4,前面my.cnf里也加了character-set-server=utf8mb4,双保险。

5.4 外键约束下的删除顺序:父表子表分不清

现象:DROP TABLE Departments直接执行失败,报错提示外键约束阻止了删除。

原因:Students和Teachers都通过Dno引用Departments,父表还存在被引用关系时,数据库不允许直接删除父表。初学时很容易忽略“先删子表再删父表”的顺序。

解决:先DROP引用它的子表,再用DROP TABLE departments;或者用DROP TABLE departments CASCADE强制级联删除,但实验报告里建议把两种方式都写出来,解释清楚CASCADE的代价是连带删掉所有引用数据。

5.5 截图不规范导致报告被退回:图题、表题、排版缺一不可

现象:电子版报告里只有一张张截图,截图的图题、编号都没有,表格也没有名字,提交后被退回重改。

原因:实验报告要求里明确写了“截图下方需有图的编号和图题,表格上方有编号及表名”,但对只关注SQL本身的同学来说,这排要求最容易漏。

解决:每做完一步立刻截图,并在截图下方标注“图1 创建数据库”“图2 创建基本表”这类编号和标题;表格上方写“表1 Students表结构”加表名。可以把截图命名规则统一成“实验序号_图序号_内容”,最后排版时按顺序插入,正文里用编号引用。段首空两个字、行文用书面语,这些都是默认要求,别在这上面丢分。

6. 验收与答辩:一份能直接拿到成绩的实验报告怎么交

6.1 验收清单:按检查项逐条过

写报告前先按验收清单跑一遍,比写完再改省时间。这五条是我每次做数据库实验都强制走完的检查项。

表2:数据库原理实验验收清单

检查项验证方法合格标准
GreatSQL服务自启动systemctl is-enabled greatsql输出enabled
SELinux彻底关闭getenforce输出Disabled
三张正式表数据完整SELECT COUNT(*) FROM 每张表行数与插入记录一致
索引创建删除有痕迹SHOW INDEX FROM StudentsStudent_Dept存在,Course_Cno被删除
查询覆盖教材全部类别按WHERE/IN/BETWEEN/LIKE/DISTINCT逐类核对截图每类至少有一条查询和对应截图

服务自启动这条最容易忽略,很多同学装完当时能启动,没配systemd enable,重启虚拟机后数据库起不来,实验三全在“连接不上数据库”里耗掉。所以验收时一定要检查systemctl is-enabled,确保enabled状态。

6.2 答辩准备:三个高频追问和对应答法

第一个追问:“为什么关闭SELinux和防火墙?”答法分两层:SELinux是强制访问控制机制,会限制mysqld进程的文件读写和网络通信权限,而且策略配置复杂,实验环境用不到;关防火墙是为了保证3306端口监听不被默认策略拦截。

第二个追问:“为什么用二进制包而不用yum安装?”答法落在观测性上:yum装完二进制分散在系统目录里,你只能看到“能用了”,但看不到DBMS内部结构;二进制包集中在独立目录,bin、lib、share一目了然,正好符合实验一“了解DBMS系统构架”的目标。

第三个追问:“SC表为什么用复合主键?”答法回到业务语义:一条选课记录由学号和课程号共同决定,(Sno, Cno)组合唯一,单独任何一列都不唯一,复合主键表达的正是这个业务约束。

这套实验流程完整走完之后,我养成了一个习惯:每次启动数据库服务,一定先systemctl status和ps -ef双确认,再开始写SQL。这个习惯救过我很多次,因为很多所谓SQL问题,根源其实是环境没起来导致的黑匣子。报告排版再好看,查不出数据也只是空壳。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进