简介郑州大学计算机与人工智能学院《数据库系统原理》课程实验报告面向2022级计算机类学生及需要完成DBMS入门实验的学习者覆盖从商用数据库系统认知到GreatSQL实操的完整流程。内容以万里数据库GreatSQL为对象包含DBMS工作原理与系统构架认识、虚拟机VMwareCentOS7环境搭建、关闭SELinux与防火墙的原因与命令、依赖包安装、二进制包下载解压与systemd服务注册以及基本表、视图、触发器、存储过程等逻辑组件的验证。报告同时给出撰写规范实验过程记录、问题与解决方法、结果分析、截图编号与图题、表格编号与表名格式并附有学时分配、实验类型等课程信息。资源包共1个docx文件约3.69MB为可直接参考排版的电子版实验报告。已有509人学习适合对照实验步骤、补齐环境配置细节或借鉴报告结构。1. 从裸机到九次实验一份数据库原理实验报告能解决什么实验室机器只装了裸的 CentOS网线一插要求你在几个学时里把一套商用 DBMS 从零拉起再把教材上的查询一路跑下来最后交一份带图号和表号的数据库原理实验报告——这是这份资源最典型的出场场景。它把某高校计算机学院《数据库系统原理》课程的九次实验整理成了完整记录从认识 DBMS、安装万里数据库 GreatSQL到建库建表建索引、交互式 SQL 查询、逻辑组件与物理组件拆解每条命令都留了截图位、编号和说明。它不是纯理论文档也不是抄一遍命令就能交差的作业本适合两类人一类是课程实验周里需要一个能照着走、能对着截图排错的模板另一类是想在虚拟机上把 GreatSQL 完整装一遍、顺便弄清information_schema里那些元数据表到底对应什么的从业者。报告末尾的图表编号、段首缩进、行文要求写得很细直接决定验收能不能一次过。2. 环境落地GreatSQL 二进制包安装、systemd 托管与启动验证实验一的核心不是敲几条命令而是把“一台干净虚拟机 → 一个能systemctl管理的数据库服务”这条链路走通。二进制包安装比源码编译快得多也比 RPM 更可控——解压到哪个目录、配置文件放哪里、数据目录挂在哪块盘全部由你自己决定。这套流程在后续八次实验里不会再变所以值得一次做对。2.1 先关 SELinux 和防火墙理由要能说出口SELinux 是强制访问控制它会对mysqld的文件读写和网络监听做策略检查实验环境里没有配套策略最容易出现“服务明明起来了本地 socket 能连、TCP 连不上”的情况。防火墙则是直接挡端口3306 没放行客户端就会超时。实验环境属于内网单机、只做验证关掉这两层是最省事的做法生产环境当然应该反过来去写策略和放行规则。# 临时把 SELinux 从 Enforcing 切到 Permissive立即生效 setenforce 0 # 永久关闭把配置文件里 SELINUX 开头的行整体替换掉 sed -i /^SELINUX/c\SELINUXdisabled /etc/selinux/config # 停掉防火墙并取消开机自启 systemctl stop firewalld systemctl disable firewalld # 复核应输出 Permissive 和 disabled getenforce systemctl is-enabled firewalldsetenforce 0是命令加参数不是赋值语句——原始记录里写成setenforce0是个典型笔误真敲下去 bash 只会回一句command not found而 SELinux 其实一直开着。参数说明0表示 Permissive只记录不拦截1表示 Enforcingsed里c\是整行替换/^SELINUX/保证只命中行首那一条不会误伤SELINUXTYPE。2.2 依赖包清单每个包都有它存在的理由一次性yum install十几个包看着粗暴但漏一个就可能在初始化阶段报错。下面这张表是我对着报错日志逐个核过的对应关系装之前扫一眼比事后查ldd快。包名缺了会怎样libaio-develInnoDB 异步 IO 初始化失败启动直接退出numactl-devel/numactl-libsNUMA 亲和性设置报错多核机器上性能不对openssl/openssl-develTLS 连接和caching_sha2_password认证不可用jemalloc/jemalloc-devel只能退回 glibc malloc高并发下内存碎片明显perl及perl-Data-Dumper、perl-Digest-MD5、perl-JSON、perl-Test-Simplemysql_secure_installation等 Perl 脚本跑不起来python2部分管理脚本仍以 py2 写报bad interpreternet-tools没有netstat排查端口时少一个顺手工具pkg-config后续装扩展时找不到库的.pc描述文件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这一行建议原样复制不要“按需裁剪”。我见过把perl系列省掉的结果初始化完成后改密码那一步卡住回头再补齐又得重来一遍。2.3 二进制包落盘位置与 systemd 服务文件包统一放/usr/local/好处是路径短、权限清晰后续所有脚本里的basedir都指向这里不会因为换了个人操作就找不到。cd /usr/local wget https://product.greatdb.com/GreatSQL-8.0.32-25/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal.tar.xz tar xf GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal.tar.xz # 建运行账号不允许登录、不分配家目录 groupadd mysql useradd -g mysql mysql -d /dev/null -s /sbin/nologin # 数据目录与日志目录属主必须是 mysql mkdir -p /var/lib/mysql chown -R mysql:mysql /var/lib/mysql /var/log chown -R mysql:mysql /usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal-d /dev/null -s /sbin/nologin这两项是安全习惯数据库账号只用来跑进程不该具备登录能力。接下来写服务文件让systemctl接管启停比每次手动mysqld_safe 靠谱得多。# /lib/systemd/system/greatsql.service [Unit] DescriptionGreatSQL Server Afternetwork.target [Service] Typeforking Usermysql Groupmysql ExecStart/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal/bin/mysqld --defaults-file/etc/my.cnf --daemonize ExecStop/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal/bin/mysqladmin --defaults-file/etc/my.cnf -uroot shutdown LimitNOFILE65535 Restarton-failure [Install] WantedBymulti-user.targetTypeforking对应--daemonize的后台化行为写成simple会导致systemctl start一直挂住不返回。LimitNOFILE65535是文件描述符上限默认 1024 在并发连接一多就报Too many open files。ExecStop用mysqladmin shutdown而不是kill是为了让 InnoDB 有机会把脏页刷盘、干净关闭。配置文件/etc/my.cnf只需要把路径和字符集钉死[mysqld] usermysql basedir/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal datadir/var/lib/mysql socket/var/lib/mysql/mysql.sock port3306 log-error/var/log/greatsql-error.log pid-file/var/lib/mysql/mysqld.pid character-set-serverutf8mb4 collation-serverutf8mb4_0900_ai_ci [client] socket/var/lib/mysql/mysql.sock default-character-setutf8mb4字符集这一项现在定好能省掉后面所有中文乱码的排查。utf8mb4与utf8mb4_0900_ai_ci配套使用前者是真正的四字节 UTF-8后者是 8.0 默认排序规则两者不一致时建表会报警告。2.4 初始化、启动与三处交叉验证数据目录是空的第一次必须初始化。常见做法是让mysqld自己生成系统表并把临时 root 密码写进错误日志。# 初始化临时密码会打印到 error log /usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal/bin/mysqld \ --initialize --usermysql --basedir/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal \ --datadir/var/lib/mysql # 从日志里捞临时密码 grep -i temporary password /var/log/greatsql-error.log # 重载 systemd 并启动 systemctl daemon-reload systemctl start greatsql systemctl status greatsqlsystemctl status只能证明 systemd 认为它活着真正的验证要三条一起看ps -ef | grep mysqld确认进程在、ss -lntp | grep mysqld确认 3306 在监听、ls /var/lib/mysql确认ibdata1、mysql、sys这些目录和文件都生成了。三条里缺任何一条问题都不在客户端而在服务端直接翻 error log 比反复重装快。提示初始化只会执行一次数据目录非空时再跑会直接报错退出。重装前先把/var/lib/mysql清干净别指望它覆盖。3. 逻辑组件与物理组件用 information_schema 把 DBMS 拆开看实验一第二部分的考点是让你说清楚“数据库里到底有哪些东西”。基本表、视图、触发器、存储过程、约束属于逻辑层能从元数据表里查出来连接池、解析器、优化器、存储引擎、日志文件属于物理层得从进程、端口、磁盘文件上去看。两层都摸一遍才算真的认识了一个 DBMS。3.1 五个逻辑组件五个能直接跑的查询元数据都躺在information_schema里这个是只读的虚拟库任何时候都能查。下面这份对照表建议存下来后面每次实验都用得上。组件对应的元数据表关键字段基本表TABLESTABLE_TYPEBASE TABLE视图VIEWSVIEW_DEFINITION触发器TRIGGERSEVENT_MANIPULATION、ACTION_STATEMENT存储过程/函数ROUTINESROUTINE_TYPE约束TABLE_CONSTRAINTS、KEY_COLUMN_USAGECONSTRAINT_TYPE-- 当前库下所有基本表顺带看引擎和行数估算 SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA DB AND TABLE_TYPE BASE TABLE; -- 视图没有记录就是空集 SELECT TABLE_SCHEMA, TABLE_NAME, VIEW_DEFINITION FROM information_schema.VIEWS WHERE TABLE_SCHEMA DB; -- 触发器 SELECT TRIGGER_NAME, EVENT_MANIPULATION, ACTION_TIMING, ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA DB; -- 存储过程把 PROCEDURE 换成 FUNCTION 就是自定义函数 SELECT ROUTINE_NAME, ROUTINE_TYPE, CREATED FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA DB AND ROUTINE_TYPE PROCEDURE; -- 约束类型 约束作用的列 SELECT CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA DB;原始记录里把SHOW FULL PROCESSLIST当成视图的查询命令这是个概念上的混淆。前者看的是当前连接会话属于连接池/线程层视图的元数据在VIEWS表里。两者都在实验一出现但对应的知识块不同写报告时分开写更容易拿到分。ROUTINES里查存储过程必须带ROUTINE_TYPEPROCEDURE否则函数会一起混进来。3.2 数据页物理存储的最小单位问“数据的存储单位是什么”答案不是行、不是表而是页。InnoDB 里默认一页 16KB所有读写都以页为单位一个页里放多行记录行与行之间用页目录定位。-- 页大小单位转成 KB 更方便看 SELECT innodb_page_size / 1024 AS page_kb; -- 数据目录位置这条决定你该去哪个路径下找 .ibd 文件 SHOW VARIABLES LIKE datadir; -- 每个库、每张表的独立表空间文件 SHOW VARIABLES LIKE innodb_file_per_table;datadir是数据根目录开了独立表空间8.0 默认开之后每个表在datadir/库名/下对应一个.ibd文件元数据在mysql.ibdredo 日志在#innodb_redo目录。搞清楚这个映射关系后面遇到“磁盘满了先清哪个”就不用猜。3.3 GreatSQL 相对原生 MySQL 的几处差异装的是 GreatSQL报告里如果只写“等价于 MySQL”内容就薄了。它在社区版基础上做的几项改进恰好都能对应到实验记录的场景第一是 MGR组复制的地理标签用来解决多机房同步时“跨机房流量压垮带宽”的问题配合新的流控机制节点抖动次数明显下降。第二是 InnoDB 并行查询在 OLAP 类统计场景下把单条查询拆到多核报告里提到的 TPC-H 测试平均提升 15 倍、最高 40 多倍就来自这里做分组统计实验时能直观感觉到。第三是事务锁结构从红黑树换成无锁哈希高并发下锁等待的尾部延迟更稳。另外还有仲裁节点省一台机器就能提高可用性、单主模式更快的选主这些属于运维向能力实验中了解即可不必真搭集群。注意并行查询对短查询、点查这类 OLTP 语句没有收益反而多一层调度开销。参数没调好时表现为小查询变慢别急着怀疑磁盘。4. 三表落地建库、建表、索引与外键挂载的先后顺序实验二、实验三合起来是整份报告的主干一个DB库、学生/课程/选课三张表、几个索引、一批演示数据。流程本身不难难的是顺序——外键必须在被引用表和数据都到位之后才能挂孤儿记录必须先清掉不然后面每次运行都卡在同一个错误上。4.1 建库字符集和排序规则一次定死-- 建库时显式指定字符集别依赖服务端默认值 CREATE DATABASE IF NOT EXISTS DB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; SHOW DATABASES; USE DB; -- 确认存储位置与建库语句 SHOW CREATE DATABASE DB; SELECT datadir;IF NOT EXISTS是后悔药脚本重复执行不会报错写进实验记录里也算一个规范点。SHOW CREATE DATABASE会回显完整的字符集定义截图放报告里比口头说明有说服力。数据库本身不占独立文件落盘位置跟随datadir真正产生文件的是后面的表。4.2 三张表字段类型要按存储需求选教材上的STUDENTS、COURSES、SC三表结构是固定的但类型宽度可以按实际数据调整这一步决定了后面会不会踩截断的坑。CREATE TABLE Students ( Sno char(9) PRIMARY KEY, Sname varchar(20) NOT NULL, Sex char(2) CHECK (Sex IN (男,女)), Birthday date, Speciality varchar(20), Dno char(4), KEY idx_stu_dno (Dno) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE Courses ( Cno char(5) PRIMARY KEY, Cname varchar(30) NOT NULL, Period smallint, Credit smallint ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE SC ( Sno char(9), Cno char(5), Grade int CHECK (Grade BETWEEN 0 AND 100), PRIMARY KEY (Sno, Cno) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;Sname用varchar而不是char(10)原因是utf8mb4下一个汉字占 34 字节char(10)只能放两三个字三字姓名直接被截断或报Data too long。SC的主键是(Sno, Cno)复合主键天然保证“一个学生一门课一条成绩”比额外加自增 id 更贴合语义。Grade上的CHECK在 8.0 已真正生效写BETWEEN 0 AND 100比0 AND 100更准确地允许 0 分。4.3 索引普通索引与唯一索引的区别要落到语句上-- 普通索引允许重复加速按系号过滤 CREATE INDEX Student_Dept ON Students (Dno); -- 唯一索引既加速又约束 CREATE UNIQUE INDEX Course_Cno ON Courses (Cno); -- 查看表上的索引 SHOW INDEX FROM Students; -- 删除索引注意 ON 表名不能省 DROP INDEX Course_Cno ON Courses;Courses.Cno上已经有主键再建同名唯一索引其实是重复的但作为实验演示“唯一索引的创建与删除”没问题。真正要注意的是DROP INDEX的语法MySQL 系必须写ON 表名写成标准 SQL 的DROP INDEX 索引名会报语法错误。索引不是越多越好SC这种写入频繁的表每加一个二级索引就多一次维护成本实验里点到这里就够了。4.4 数据填充与外键挂载顺序错了必翻车插入顺序必须是“被引用表在前、引用表在后”外键挂载必须在数据补齐之后。原始记录里先插SC再ALTER TABLE ... ADD FOREIGN KEY而SC中存在Students里没有的学号加约束时必然报 1452。-- 1) 先插被引用表 INSERT INTO Students VALUES (201705001,张一,男,1999-12-16,计算机,CS), (201705002,李二,女,1999-01-01,软件工程,SE), (201705003,王三,男,1999-05-24,计算机,CS); INSERT INTO Courses VALUES (CS101,计算机科学导论,2,1), (CS102,数据库系统,4,4), (CS103,操作系统,4,3); -- 2) 再插引用表且学号必须在上面的集合里 INSERT INTO SC VALUES (201705001,CS101,89), (201705002,CS102,92), (201705003,CS101,88); -- 3) 数据齐了再挂外键 ALTER TABLE SC ADD CONSTRAINT fk_sc_stu FOREIGN KEY (Sno) REFERENCES Students(Sno) ON UPDATE CASCADE ON DELETE CASCADE, ADD CONSTRAINT fk_sc_course FOREIGN KEY (Cno) REFERENCES Courses(Cno);ON UPDATE CASCADE ON DELETE CASCADE让学号变更、学生删除时选课记录跟着走实验报告里写上这一句能体现你考虑过级联语义。如果不加删学生时会被外键挡住并报 1451。挂完约束后用SHOW CREATE TABLE SC复核一遍外键名和级联规则都会回显这是最省事的自检方式。4.5 落库之后的第一次验证建完不等于对跑几条查询确认数据真进去了SELECT COUNT(*) AS stu_cnt FROM Students; SELECT Sno, Sname, YEAR(Birthday) AS birth_year FROM Students; SELECT * FROM SC WHERE Grade 60;第一条对数量第二条验证date类型能被YEAR()正确解析第三条提前确认“不及格查询”有结果可查。三条都过再往下写复杂查询才有意义。5. 避坑与排查安装、建表、外键与日期格式的五个翻车点这一章是按“现象 → 原因 → 解决”整理的实录五个点覆盖了这份实验报告里九成以上的报错。写完实验再回头对一遍比出问题现查快得多。5.1 服务起不来status 显示 failed现象systemctl start greatsql返回失败status里只有一行Job for greatsql.service failed没有细节。原因真正的错误在/var/log/greatsql-error.log里systemd 只负责转述退出码。最常见的是数据目录属主不对用 root 跑过初始化或者datadir非空导致重复初始化。解决先tail -50 /var/log/greatsql-error.log看到Permission denied就chown -R mysql:mysql /var/lib/mysql看到data directory has files就清空目录重新初始化。养成习惯任何服务启动失败先看它自己的日志再看 systemd 的。5.2 中文姓名插入报 Data too long现象INSERT INTO Students VALUES(201705001,张一,...)报ERROR 1406 (22001): Data too long for column Sname。原因字段定义成char(10)utf8mb4下每个汉字最多占 4 字节三字姓名需要的字节数超过 10严格模式下直接拒绝。解决改成varchar(20)或varchar(30)长度按“字符数”而不是“字节数”估算。如果表已经建好用ALTER TABLE Students MODIFY Sname varchar(20) NOT NULL;改历史数据不会丢。5.3 加外键报 1452找不到父行现象ALTER TABLE SC ADD FOREIGN KEY (Sno) REFERENCES Students(Sno)报ERROR 1452: Cannot add or update a child row。原因SC里存在Students中不存在的学号也就是孤儿记录。原始记录里学生表只插了 001、002选课表却插了 003一对就穿帮。解决先用反连接把孤儿揪出来再决定是补父表数据还是删子表记录。-- 找出 SC 里在 Students 中找不到对应学号的行 SELECT s.Sno, s.Cno FROM SC s LEFT JOIN Students stu ON s.Sno stu.Sno WHERE stu.Sno IS NULL;查出来是数据缺失就补Students是脏数据就删掉然后重新ALTER TABLE。先查后改不要靠猜。5.4 日期写成下划线报 Incorrect date value现象INSERT ... 1999_12_16报ERROR 1292 (22007): Incorrect date value。原因date类型只认YYYY-MM-DD格式下划线是变量命名习惯带进来的SQL 解析器不认。解决统一改成1999-12-16。批量导入的 CSV 也同理导入前先sed -i s/_/-/g把日期列洗一遍别在LOAD DATA里做函数转换那样索引和类型推断都会出问题。5.5 删表顺序反了报 1451现象DROP TABLE Students;报ERROR 1451: Cannot delete or update a parent row。原因SC还挂着指向Students的外键父表不能先删。解决先删子表再删父表或者临时SET FOREIGN_KEY_CHECKS0;关掉检查仅限实验环境删完再打开。更稳的写法是建表时就规划好DROP TABLE IF EXISTS SC, Students, Courses;的顺序把子表放最前面。注意FOREIGN_KEY_CHECKS0是会话级变量只影响当前连接别以为它会持久化。用完记得显式设回 1。6. 交互式 SQL 与验收技巧把查询跑对把截图排整齐实验三往后全是查询和更新教材例题多但结构就那几类单表过滤、IN/BETWEEN范围、连接、分组统计。真正容易丢分的不是写不出 SQL而是结果对不上、截图糊、图号漏。这里给一套我自己每次交实验都走的验证顺序。先跑通不带WHERE的全表查询确认数据量再逐层加条件缩小范围。日期区间一律用YEAR()或BETWEEN而不是字符串比较避免隐式转换导致索引失效-- 出生年份落在 1997~1999 之间的学生 SELECT Sname, Speciality FROM Students WHERE YEAR(Birthday) BETWEEN 1997 AND 1999; -- 按课程分组统计平均分、最高分、选课人数 SELECT c.Cname, COUNT(*) AS stu_num, ROUND(AVG(s.Grade),1) AS avg_grade, MAX(s.Grade) AS max_grade FROM SC s JOIN Courses c ON s.Cno c.Cno GROUP BY c.Cno, c.Cname HAVING COUNT(*) 2 ORDER BY avg_grade DESC; -- 用 EXPLAIN 确认过滤条件是否走到索引 EXPLAIN SELECT * FROM Students WHERE Dno CS;GROUP BY后面把c.Cname一起带上是为了兼容ONLY_FULL_GROUP_BY模式只写c.Cno在严格模式下会报错。EXPLAIN的type列出现ALL说明走了全表扫描key列为NULL说明索引没命中这时候就该检查条件字段和索引字段是不是同一个类型。截图和排版这块验收标准其实写得很明确照着做基本一次过项目要求常犯的错图图下方有编号和图题图题写图上、编号断号表表上方有编号和表名只有表头没有编号正文段首空两字、书面语直接贴命令行原文过程写遇到的问题与更正只贴成功结果最后说个我自己的习惯每次交报告前把每条命令在干净环境里重跑一遍从systemctl status到最后的EXPLAIN一条不跳。有次图 12 的外键语句在别人的机器上直接报错就是因为那台机器的Students里少了一条数据而我的截图是补完数据之后拍的——图对不上命令返工重做了一整天。从那以后我每次整理实验记录都强制走一遍“清库 → 按顺序执行 → 逐条截图”的流程宁可多花半小时也不留对不上的图。希望帮到你。本文还有配套的精品资源点击获取