数据库原理实验全拆解:从GreatSQL安装到SQL查询与索引优化
简介ZZU郑州大学计算机与人工智能学院《数据库系统原理》实验报告完整版2023-2024第二学期适用于该校计算机类本科生及需要完成同类数据库实验的读者。报告以实验一“认识DBMS系统”为主线系统梳理了商用数据库管理系统万里数据库GreatSQL的安装、启动、停止等操作并详细记录关闭SELinux与防火墙的原因和命令、安装依赖包、下载解压二进制包、配置systemd服务、创建mysql用户及启动服务等完整流程。每个环节均配有命令、截图编号和结果说明同时对数据库系统的逻辑组件基本表、视图、触发器、存储过程、约束与物理存储方式作了归纳便于理解数据库底层运行机制。整份资源仅1个docx文档压缩包大小3.69MB内容结构清晰从实验目的、实验类型、学时分配到操作步骤和结果分析一应俱全。已有509人学习可作为课程实验报告撰写、数据库环境搭建和排错思路的重要参考。1. 认识DBMS这份数据库实验报告值不值得照着做数据库原理这门课理论听懂了不算数真到虚拟机里把DBMS装起来、建库建表、插数据、写查询才算把教科书里的概念落到手上。这份实验报告来自某高校计算机专业的《数据库系统原理》课程核心是用GreatSQL把三个实验完整走了一遍认识DBMS、创建数据库表和索引、交互式SQL查询。最大的看点是它把安装、配置、启动、建表、查询从零到一记录得很完整——对于正在做同款实验的学生可以直接对照步骤抄作业、补截图、填问题总结对于想快速搭一套MySQL系数据库环境的开发者这里也排掉了一大半安装阶段的坑。报告本身是课程作业但技术流程是通用的这才有拆的价值。2. GreatSQL安装与启动二进制包部署和服务管理的完整链路实验一的实质任务是把GreatSQL装进CentOS7虚拟机再用systemctl把它管起来。装MySQL系数据库通常有四条路yum/rpm包、docker镜像、源码编译、二进制解压。这份报告选的是二进制minimal包理由很简单——官方编译好的解压即用不碰编译期依赖minimal裁剪了调试组件虚拟机里跑更轻。用yum装的社区版MySQL版本往往比较旧实验里要验证8.0.32的并行查询和MGR特性就体验不到了。所以选型上二进制包是教学环境里最稳的。2.1 环境准备关闭SELinux和防火墙到底关的是什么实验第一步先把系统的两道安全闸门给关了setenforce 0 sed -i s/^SELINUX.*/SELINUXdisabled/ /etc/selinux/config systemctl stop firewalld systemctl disable firewalldsetenforce 0是临时把SELinux切到permissive立即生效sed那一行把配置文件里的SELINUXenforcing改成disabled重启后仍然生效。为什么要关SELinux因为mysqld进程要写/var/lib/mysql、要监听3306端口、要读写socket文件这三类操作都在SELinux的策略管辖范围内策略没配好就会看到数据库启动失败或者连不上日志里只有一句Permission denied非常难排查。防火墙同理3306被挡客户端就连不上。需要说清楚这个“关”是教学环境的省事做法。生产环境里正确姿势是配置SELinux布尔值和firewalld放行3306/tcp而不是一刀切。报告里那句“关闭可以简化配置、提高性能”其实只说对了一半严格的SELinux策略确实有性能开销但虚拟机里做实验差别基本可以忽略。2.2 依赖包安装这串包名不是白给的依赖包用一条yum命令装齐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这里面有几个是硬依赖缺了启动必翻车。libaio-devel对应InnoDB的异步IO没有它在高并发下会报io_setup失败numactl系列是NUMA内存分配策略工具多路物理机必备虚拟机里装了也不亏jemalloc是官方推荐的内存分配器替换glibc的malloc能减少内存碎片对长期运行的数据库进程很关键openssl-devel是SSL/TLS通信的库MySQL 8.0默认开启加密连接缺了连配置都过不去。perl和python2主要是给一些管理脚本用的。正常装完不会有输出告警。如果看到“No package python2 available”不用慌CentOS 7自带python2注意别和编译类报错搞混。这里照抄报告的命令就行顺序不要乱。2.3 解压二进制包与systemd服务文件进入安装目录拉包、解压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版本号8.0.32-25是8.0系列里的稳定迭代glibc2.17说明它适配CentOS7的系统库。解压后目录名带完整版本字符串后续basedir就指向它最好别改名字免得和文档对不上。我一般不会把目录重命名成mysql保持版本号在路径里升级时一目了然。接下来要把GreatSQL注册成systemd服务手工创建/lib/systemd/system/greatsql.service。按最小化配置内容可以写成这样[Unit] DescriptionGreatSQL Server Afternetwork.target [Service] Typesimple Usermysql Groupmysql ExecStart/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal/bin/mysqld --defaults-file/etc/my.cnf LimitNOFILE65535 Restarton-failure [Install] WantedBymulti-user.targetTypesimple告诉systemdExecStart启动的这个mysqld进程就是服务本体User和Group指定用mysql账号运行避免用root跑数据库LimitNOFILE调高文件描述符上限省得高并发下报Too many open files。Restarton-failure表示非正常退出时自动拉起实验里偶尔写错配置导致mysqld崩溃它能自动救回来。写完执行systemctl daemon-reload让systemd重新读取单元文件。2.4 创建mysql用户、目录和my.cnf数据库进程不能跑在root下所以要建一个不能登录的系统账号/sbin/groupadd mysql /sbin/useradd -g mysql mysql -d /dev/null -s /sbin/nologin mkdir -p /var/lib/mysql /var/log/mysql /var/run/mysqld chown -R mysql:mysql /var/lib/mysql /var/log/mysql /var/run/mysqlduseradd的-d /dev/null -s /sbin/nologin是故意把家目录和shell都禁掉这样mysql用户只能作为服务账号存在即使进程被攻破也拿不到交互shell。数据目录/var/lib/mysql、错误日志目录/var/log/mysql、socket文件目录/var/run/mysqld这三个目录都必须提前建好并且属主改成mysql:mysql否则启动时连目录都写不进去。然后是全局配置/etc/my.cnf。实验报告里只说“编辑”没说内容这里按最小化配置补一个能跑的版本[mysqld] basedir/usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal datadir/var/lib/mysql socket/tmp/mysql.sock port3306 usermysql log-error/var/log/mysql/mysql.log pid-file/var/run/mysqld/mysqld.pidbasedir和datadir必须和实际路径完全一致socket选/tmp/mysql.sock是兼容大多数客户端工具的默认值pid-file指向/var/run/mysqld这个目录上面已经建好。如果以后要上MGR还要再配server_id、gtid_mode这些参数实验阶段先不用。2.5 初始化数据目录安装中最容易漏的一步实验报告里从解压直接跳到启动漏掉了二进制安装最关键的初始化步骤。二进制包解压出来/var/lib/mysql是空的mysqld第一次启动会直接报错退出错误日志里写着“Data directory not initialized, you can use --initialize”。我一般会先做一次无密码初始化cd /usr/local/GreatSQL-8.0.32-25-Linux-glibc2.17-x86_64-minimal bin/mysqld --defaults-file/etc/my.cnf --initialize-insecure --usermysql--initialize-insecure会生成一个root空密码账号适合实验环境登录时不用去翻日志找随机密码生产上则用--initialize它会生成随机密码并写进错误日志。初始化完成后/var/lib/mysql下会出现ibdata1、mysql.ibd、performance_schema等系统表空间文件。这一步如果报缺少共享库回2.2补依赖包就行。2.6 启动、验证与日常管理初始化到位后用systemd启动并确认状态systemctl daemon-reload systemctl start greatsql systemctl status greatsql ps -ef | grep mysqld ss -lntp | grep 3306 ls -l /var/lib/mysqlsystemctl status输出active (running)基本就算过了但我会习惯再补两刀ps确认mysqld进程确实存在且是mysql用户ss -lntp看到3306在监听才说明网络层通了。最后ls一下数据目录看到ibdata1和mysql目录心里才踏实。日常管理就是三件套systemctl start greatsql、systemctl stop greatsql、systemctl restart greatsql。stop时会等待事务落盘慢是正常的不要反复点start。如果启动失败优先看错误日志尾部tail -50 /var/log/mysql/mysql.log八成能找到SELinux权限或初始化遗漏的线索。这套流程走下来后面实验二、三才有稳定的运行环境。3. 数据库的逻辑组件与物理存储用SQL把黑匣子看清实验一的后半段是概念验证把数据库拆成逻辑组件和物理组件逐一对号入座。逻辑组件是用户在SQL层能直接操作的对象物理组件则是磁盘上真实的文件结构。这一章的核心思路就一个——概念不要背要用SQL去information_schema里查一遍。3.1 逻辑组件五类对象的定义与查看命令数据库的逻辑组件包括基本表、视图、触发器、存储过程和约束。它们都是“意义上存在”的对象真正的落脚点是数据字典。基本表是真实存储数据的结构一个逻辑表对应磁盘上一个或多个文件。视图是虚拟表它不存数据本质是一条被保存下来的查询语句查询视图时动态执行底层SQL。触发器是绑定在表上的事件钩子INSERT、UPDATE、DELETE发生时自动触发。存储过程是预编译的SQL语句集合适合封装复杂业务逻辑减少客户端和服务器间的往返。约束是数据完整性的规则包括主键、外键、唯一、非空、CHECK等。查看这些组件最直接的办法是查询information_schema它是数据库自带的数据字典SHOW TABLES; SELECT TABLE_NAME FROM information_schema.VIEWS WHERE TABLE_SCHEMADB; SELECT TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMADB; SELECT ROUTINE_NAME FROM information_schema.ROUTINES WHERE ROUTINE_TYPEPROCEDURE AND ROUTINE_SCHEMADB; SELECT TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMADB;其中VIEWS表存视图定义TRIGGERS表存触发器的触发事件和关联表ROUTINES表存存储过程TABLE_CONSTRAINTS表把每个约束的类型都列出来。原报告里查看视图用的是SHOW FULL PROCESSLIST那是在看连接进程和视图没关系。更严谨的写法是上面第一条的SELECT拆这份报告时我特意把这处圈了出来这类“命令张冠李戴”在课程作业里很常见正好说明对照数据字典查组件比截图更有说服力。3.2 物理组件数据页、表空间和日志文件物理组件的核心是数据页。InnoDB的整个存储体系建立在页之上默认每页16KB表数据以B树形式组织在这些页里。页再往上是一系列文件每张表独立的.ibd文件开启innodb_file_per_table时、系统表空间ibdata1、redo日志文件、undo日志文件以及各种元数据文件。用系统变量把物理结构验证一遍SHOW VARIABLES LIKE innodb_page_size; SHOW VARIABLES LIKE innodb_data_file_path; SHOW VARIABLES LIKE innodb_file_per_table; SHOW VARIABLES LIKE innodb_log_files_in_group;innodb_page_size返回16384就是16KBinnodb_file_per_table为ON说明每张表一个.ibdinnodb_data_file_path指向ibdata1的路径和初始大小redo日志默认两组对应#innodb_redo目录。数据存放位置怎么确定路径由datadir变量决定实验配置里写的是/var/lib/mysql。用ls -lh /var/lib/mysql看一眼ibdata1和以库名命名的子目录都在明面上。物理层面的认识对后续性能排查很有用——一张表查得快慢本质上是在B树索引页上做的二分查找次数页分裂多、碎片多查询自然慢。实验报告不需要写太深但能说出“存储单位是数据页默认16KB一个页可能包含多行记录”已经比背概念强很多。3.3 GreatSQL特性速览为什么课程选它而不是社区版MySQL实验一里专门列了GreatSQL的几个工具特性这不是凑字数而是这版数据库和社区版MySQL的差异化卖点。MGRGroup Replication提供了高可用方案GreatSQL在此基础上加了地理标签解决多机房数据同步改进了流控算法大事务能及时检测出来避免MGR集群被一个超大事务拖死。InnoDB并行查询针对OLAP场景优化据官方测试TPC-H性能平均提升15倍最高40多倍做实验跑复杂统计查询时感觉最明显。事务锁从红黑树改成无锁哈希结构高并发写入时锁竞争更小。仲裁节点则是在不增加数据节点的情况下提升可用性降低服务器成本。课程选它而不是社区版MySQL教学上有个明显好处学生既能接触标准SQL语法又能观察到商用增强特性比如单主模式的快速选主、流控机制这些都在社区版里见不到。实验环境虽然用不起多节点集群但至少能在文档和初始化脚本里看到这些增强点的存在。对学习者来说重点还是先把标准SQL练熟MGR、并行查询这类特性作为“以后做DBA”的方向了解即可。3.4 一次性体检把组件信息导出成报告素材做实验报告时最烦的是截图不齐、分析没依据。这里可以写一条万能体检语句把当前库里的对象一次清点完SELECT TABLE_NAME, TABLE_TYPE, ENGINE, TABLE_ROWS, DATA_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMADB;TABLE_TYPE区分BASE TABLE和VIEWENGINE列出每张表的存储引擎TABLE_ROWS是估算行数不是精确值DATA_LENGTH是数据占用字节数。把这条查询结果放进实验报告的“结果分析”再配一条SHOW VARIABLES LIKE innodb_page_size物理存储和逻辑对象两块就都有实锤了。如果想把输出存下来慢慢看还可以用mysql客户端重定向mysql -uroot -p DB -e 查询语句 component_report.txt。这章的任务就是把“看数据库”这个动作从黑匣子变成可重复执行的SQL。4. 创建数据库、表和索引DDL的规范与三个常见错实验二开始动手建东西。这一章的SQL都不难难在规范性和几个一不留神就翻车的语法细节。我会按照“建库→建表→填数据→建索引→删表”的顺序拆同时把常见误用单独标出来。4.1 创建数据库并确认存储位置第一条SQL是最简单的但很多人建完库就忘了看它落在哪CREATE DATABASE DB; SHOW DATABASES; USE DB;CREATE DATABASE创建的是逻辑库。在InnoDB体系下对应datadir下会新建一个名为DB的目录后续表文件都放里面。要确认存储位置可以用系统命令看物理路径ls -ld /var/lib/mysql/DB数据库文件个数和大小建表前可以先查information_schema.tables确认库存在建表后再通过SHOW TABLE STATUS看到每个表的数据大小和行数。实验报告要求“观察数据库文件个数、大小”其实就是这几条命令的输出。顺手执行SHOW CREATE DATABASE DB;还能看到库的默认字符集比如utf8mb4这对中文数据的写入很重要。4.2 基本表结构定长字符串、主键与NOT NULL实验二先建了三张教学表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) );上面每张表都定义了主键。STUDENTS单列主键SnoSC用复合主键(Sno,Cno)表示“一个学生的一门课只有一条成绩”这是业务规则的硬约束。Sname和Cname加NOT NULL姓名和课程名不允许空值。使用char而不是varchar是因为学号、课程号这种长度固定且经常作为连接条件的列定长字符串比较稳定索引也更紧凑姓名虽然长度会变但教学表里统一定长能减少偏移计算真实系统一般用varchar。三个常见错第一实验报告初稿里出现过全角逗号“id intcid int”在SQL里只有半角逗号合法从中文Word复制粘贴代码时最容易带进来第二Sno用char(9)还是char(12)必须和后续所有相关表保持一致否则加外键时直接报错第三Birthday列必须用DATE类型如果图省事存成字符串后面YEAR()函数和BETWEEN日期比较都会出问题。建表之后用SHOW TABLE STATUS验证一下SHOW TABLE STATUS LIKE STUDENTS;重点看Engine列是不是InnoDBRows列的行数Data_length列的数据字节数。这些数字可以直接写进实验报告的“结果分析”。4.3 批量填充数据INSERT多行的写法表建好用多行VALUES一次性填充INSERT INTO STUDENTS VALUES (201705001, 张华, 男, 1999-12-16, 计算机, CS), (201705002, 张晓霞, 女, 1999-01-01, 软件工程, SE), (201706001, 李玉, 女, 1999-10-17, 数学, MA); INSERT INTO COURSES VALUES (CS101, 计算机科学导论, 2, 1), (CS102, 数据库系统, 4, 4), (CS103, 操作系统, 4, 3); INSERT INTO SC VALUES (201705001, CS101, 89), (201705002, CS102, 92), (201705003, CS101, 88);要点有两个。一是VALUES后面用逗号分隔多个元组一条语句插多行比逐条INSERT快很多二是日期必须写成1999-12-16这种ISO格式用下划线或斜杠都可能被MySQL转成0值日期。如果表里部分列允许空值建议写成带列名的形式INSERT INTO STUDENTS(Sno, Sname, Sex) VALUES (...)字段顺序变化时不容易张冠李戴。插完后跑SELECT * FROM STUDENTS确认行数和内容这一步别省。4.4 索引的创建和删除语法差异与选型实验二要求在Dno上建普通索引在Cno上建唯一索引CREATE INDEX Student_Dept ON Students(Dno); CREATE UNIQUE INDEX Course_Cno ON Courses(Cno); DROP INDEX Course_Cno ON Courses;Dno是专业方向的查询条件建索引能减少全表扫描Cno是课程主键本身已有主键索引这里再建UNIQUE INDEX是演示唯一性约束的用法。删除索引在MySQL里的语法是DROP INDEX 索引名 ON 表名注意和SQL Server的DROP INDEX 表名.索引名正好相反这个差异在跨数据库迁移时特别容易踩。索引不是越多越好写操作多的表索引太密反而拖慢INSERT和UPDATE实验里建这两个就够演示了。4.5 删除表时cascade的误区实验二初稿里写的是drop table students cascade;但这是Oracle/SQL Server的遗产语法MySQL系根本不支持直接执行会报语法错误。MySQL删除表就是DROP TABLE STUDENTS; DROP TABLE Courses; DROP TABLE SC;有外键关系时要先删子表SC再删父表STUDENTS、Courses。如果顺序反了MySQL会报“cannot drop table referenced by a foreign key constraint”。实验二阶段三张表还没有外键随便删到实验三有了外键这个顺序就非常重要了。这里正好埋一个伏笔留到第5章排查部分展开。5. 交互式SQL实战与常见问题排查数据填充、查询与五个坑实验三把难度提了一档先建六张有关联的表再填充数据最后跑各种查询和更新。这一章我会先给完整的表结构和外键关系再走数据填充最后把查询套路过一遍——真正的重头戏是5.4里的五条踩坑实录。5.1 六张表和它们的外键关系实验三的数据模型是一个简化版教务系统departments院系、teachers教师、students学生、courses课程、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 IN (男, 女)), 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 );SC和Teaches是关联表各自带外键。原报告里Teaches一开始没写外键后面用ALTER补这里我保持同样的流程先建一个暂时没有外键的版本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) );TCsores这列名原报告就这么写的明显是TCscore的笔误不影响实验。随后用ALTER补齐Teaches和另外两张表的外键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);外键关系如果画成表就是下面这样外键列所属子表引用父表SC.SnoSCStudentsSC.CnoSCCoursesTeaches.TnoTeachesTeachersTeaches.CnoTeachesCoursesStudents.DnoStudentsDepartmentsTeachers.DnoTeachersDepartments需要特别注意MySQL对参照列的类型要求非常严格子表和父表的列数据类型必须完全一致比如SC.Sno和Students.Sno都得是char(12)char(10)配char(12)都会报1215错误。CHECK约束在8.0.16之后才真正生效GreatSQL 8.0.32没问题如果换到老版本MySQL这个CHECK会被静默忽略这是版本差异不是SQL写错。5.2 插入数据先父后子日期格式别偷懒有外键之后插入顺序是硬约束先父表后子表。所以正确顺序是departments → teachers/students → courses → sc/teaches。父表数据不存在时子表插入会直接触发1452外键约束失败。贴一段示范INSERT INTO departments VALUES (CS, 计算机系, 05001), (MA, 数学系, 06001), (PH, 物理系, 07001), (CH, 化学系, 08001); INSERT INTO teachers VALUES (05001, 张海峰, 男, 1969-02-21, 教授, CS), (05002, 刘晓明, 男, 1978-10-06, 副教授, CS); INSERT INTO students VALUES (201705001, 张华, 1999-12-16, 计算机, CS, 男), (201705002, 李玉, 1998-10-17, 计算机, CS, 女); INSERT INTO courses VALUES (cs101, 计算机科学导论, 2, 1), (cs102, C语言, 4, 3); INSERT INTO sc VALUES (201705001, cs101, 89), (201705002, cs101, 91);插入时最常见的错误就是把日期写成1999_12_16这种下划线格式。MySQL的宽松模式会把这种字符串转成0000-00-00等到按年份查询时结果为空数据还不报错。更稳妥的是统一用1999-12-16或者显式调用STR_TO_DATE(1999_12_16, %Y_%m_%d)。另外性别字段和职称字段存的是中文字符串插入和查询时务必两边一致比如男和男 中间带个空格都匹配不上。5.3 查询套路WHERE、日期计算、BETWEEN与IN实验三的查询覆盖了SQL入门最重要的几个子句SELECT * FROM Courses; SELECT Sname, 2024 - YEAR(Birthday) AS Age FROM Students; SELECT Tname, Sex FROM Teachers WHERE Title 讲师; SELECT DISTINCT Sno FROM SC WHERE Grade 60; SELECT Sname, Speciality FROM Students WHERE YEAR(Birthday) BETWEEN 1997 AND 1999; SELECT Sno, Sname FROM Students WHERE Speciality IN (计算机, 软件工程); SELECT Sno, Sname FROM Students WHERE Speciality NOT IN (计算机, 软件工程);YEAR(Birthday)从日期里提取年份2024减去年份得到年龄这里用别名AS Age。BETWEEN是闭区间等价于1997 AND 1999。IN本质上是多个OR的简写NOT IN则是取反。DISTINCT去重很关键查“成绩不及格的学生学号”不去重会重复因为一个学生可能多门课不及格。还有个细节WHERE子句不能直接引用SELECT里定义的别名比如WHERE Age 20会报错因为WHERE在逻辑上先于SELECT执行。更新操作相对简单但涉及表SC有复合主键DELETE和UPDATE都要带全条件UPDATE SC SET Grade Grade 2 WHERE Grade 60; DELETE FROM SC WHERE Sno 201705001 AND Cno cs301;执行前先跑一遍等价的SELECT看受影响行数能避免把全表改错。这个习惯在真实运维里比任何语法知识都保命。5.4 常见问题排查五条踩坑实录这一节把前面几章埋下的坑集中复盘每条都是“现象→原因→解决”的结构。第一坑systemctl start greatsql后进程立刻消失。现象是服务状态显示failed日志最后一行写着Data directory not initialized。原因是二进制包解压后没有初始化数据目录mysqld拒绝直接干活。解决方法是补一次bin/mysqld --defaults-file/etc/my.cnf --initialize-insecure --usermysql再启动。第二坑CREATE TABLE报语法错误error 1064。现象是SQL语句粘贴进去就报错光标常常停在一个中文标点上。原因是全角逗号“”混进了SQL常见于中文输入法没切回来。解决方法是把编辑器显示标点打开或者重新手敲一遍SQL不要直接粘贴Word里的代码。实验二原稿里出现“id intcid int”就是典型。第三坑建外键时报1215 Cannot add foreign key constraint。现象是ALTER TABLE ADD FOREIGN KEY执行失败。原因是子表SC.Sno和父表Students.Sno类型不一致比如一个char(9)一个char(12)或者字符集、排序规则不同。解决方法是执行SHOW CREATE TABLE Students查看Sno定义改成完全匹配的类型必要时连COLLATE一并统一。第四坑日期插入后变成0000-00-00。现象是INSERT成功但SELECT显示日期全是0按年份查也查不到。原因是字符串格式不合法MySQL宽松模式下没有抛错而是把非法日期归零。解决方法是改用1999-12-16标准格式或者用STR_TO_DATE显式转换同时可以查sql_mode把STRICT_TRANS_TABLES加进去让非法日期直接报错而不是静默归零。第五坑DROP TABLE带CASCADE报语法错误。现象是drop table students cascade;执行失败。原因是CASCADE是其他数据库的方言MySQL的DROP TABLE不支持这个关键字。解决方法是去掉CASCADE直接删顺序按先子后父。如果确实需要保留外键引用可以考虑先删外键约束再删表但教学实验里用不上。这五条是老手在部署里都会碰到的类型。排错顺序也统一先看错误码再查对应对象的定义最后检查字符集和数据类型。养成这个习惯数据库实验基本不会有解决不了的问题。6. 把实验变成可验证的套路SHOW INDEX与EXPLAIN快速巡检前面五章把安装、建表、查询都走了一遍最后一个技巧能让你在做实验报告时多一层说服力用SHOW INDEX和EXPLAIN验证索引到底有没有生效。实验二建了Student_Dept和Course_Cno两个索引实验三的查询跑得飞快但你凭什么说索引起了作用凭EXPLAIN执行计划。SHOW INDEX FROM Students; SHOW INDEX FROM Courses;这条输出里每一行代表一个索引Key_name是索引名Seq_in_index是索引内字段顺序Column_name是列名Non_unique为0表示唯一索引。建完Student_Dept后这里应该能看到一条名为Student_Dept的记录。然后再验证查询计划EXPLAIN SELECT * FROM Students WHERE Dno CS; EXPLAIN SELECT * FROM SC WHERE Sno 201705001;EXPLAIN结果里的type字段是关键。typeALL表示全表扫描说明索引没被用上typeref或const表示走了索引ref是普通索引等值命中的典型值const是主键或唯一索引等值命中的典型值。如果建了索引但type还是ALL最常见的原因是列上做了函数运算比如WHERE YEAR(Birthday)1999这种写法会让索引失效改成WHERE Birthday BETWEEN 1999-01-01 AND 1999-12-31才能命中索引。把这两条EXPLAIN输出放进实验报告的结果分析里比单纯说“查询成功”强得多。把这套动作固化下来是我拆完这份报告之后的直接收获。以前做实验总是建完表就开始写查询出问题全靠猜后来我强制自己每次装完数据库、建完表、写完SQL都按同一个顺序走一遍systemctl status检查服务、SHOW TABLE STATUS看表规模、EXPLAIN看执行计划。这个三件套走完几乎所有低级错误都能提前暴露而不是等数据填完才发现表结构错了。拆这份实验报告的过程里最有价值的就是把这三步串成了一条固定巡检链路。如果你正要动手做同类的数据库实验建议你也把这三步变成自己的习惯希望帮到你。本文还有配套的精品资源点击获取