☰
大连理工软件数据库openGauss上机作业实战:从建表到存储过程避坑指南
2026/10/3 6:37:15 网站建设 项目流程

简介:这份资源是大连理工大学软件学院数据库系统课程的上机作业报告,基于华为 OpenGauss 数据库管理系统编写,面向正在学习数据库课程、需要完成上机实验或撰写实验报告的高校学生。报告内容覆盖数据库系统课程的核心实验模块,包括 DDL 数据定义语言(创建数据库、表、索引与视图)、DML 数据操作语言(数据插入、更新与删除)、数据查询(单表查询、聚合查询、多表查询、子查询与集合查询)、索引操作以及事务的并发控制等,并配有预备知识、实验任务与 SQL 代码及对应结果,便于对照理解与复盘。资源包共 1 个 docx 文件,约 1.36MB,结构完整、章节清晰,可直接作为实验报告模板或学习参考。目前已有 619 人学习下载,适合需要系统掌握 OpenGauss 基本操作、查漏补缺或整理实验文档的软件学院学生使用。

1. 从一份上机作业说起:openGauss 到底要练什么

很多人第一次接触大连理工软件数据库 opengauss 上机作业报告,脑子里冒出来的第一个问题不是 SQL 怎么写,而是「这玩意儿跟 MySQL 到底差在哪」。我当年也是这么想的,结果第一次上机就翻车——照着 MySQL 的习惯写AUTO_INCREMENT,openGauss 直接报错,因为人家用的是SERIAL或者IDENTITY。openGauss 是华为开源的关系型数据库,内核源自 PostgreSQL,所以它的 SQL 语法、数据类型、系统表设计都带着明显的 PG 血统,但又做了不少企业级增强,比如列存、MOT 内存表、AI 能力集成。这份上机作业的核心,说白了就是让你用 DDL 建表、用 DML 增删改查、用约束和事务把数据管起来,最后能跑出一份逻辑自洽的报告。适合谁?软件工程、计算机专业正在上数据库课的学生,以及想从 MySQL 迁移到国产数据库、需要快速摸清 openGauss 脾气的开发者。下面我按实际动手顺序,把环境、建表、查询、存储过程、避坑一条线讲透。

2. 环境准备与连接:别在第一步卡住

2.1 openGauss 安装部署流程的两种走法

openGauss 的安装部署流程,常见做法有两种:一种是直接用官方提供的 Docker 镜像,适合本地快速验证;另一种是在 Linux 服务器上跑企业版安装脚本,适合需要完整功能的场景。上机作业一般用 Docker 就够了,省去内核参数调优的麻烦。我一般会先拉镜像再起容器,命令如下:

# 拉取 openGauss 官方镜像(版本按课程要求选,这里以 5.0.0 为例) docker pull opengauss/opengauss:5.0.0 # 启动容器,映射 5432 端口,设置初始密码 docker run --name opengauss \ -e GS_PASSWORD=Enmo@123 \ -p 5432:5432 \ -d opengauss/opengauss:5.0.0 # 进入容器 docker exec -it opengauss bash # 切换到 omm 用户(openGauss 的初始超级用户) su - omm # 用 gsql 连接本地数据库 gsql -d postgres -p 5432

这段脚本的逻辑很直白:拉镜像、起容器、进容器、切用户、连数据库。参数上要注意GS_PASSWORD必须包含大小写字母、数字和特殊字符,否则容器起不来,这是 openGauss 的密码复杂度强制要求,跟 MySQL 的宽松策略完全不同。端口映射-p 5432:5432是为了让宿主机上的客户端工具也能连,如果你只用容器内的 gsql,不映射也行。su - omm这一步不能省,openGauss 不允许 root 直接跑 gsql,这是安全设计。

2.2 用 gsql 和客户端工具连上数据库

连上之后,你可以用 gsql 交互式执行 SQL,也可以用 DBeaver、Navicat 这类图形化工具。openGauss 兼容 PostgreSQL 的 JDBC 驱动,所以 DBeaver 里选 PostgreSQL 驱动就能连。连接参数如下:

参数值说明
主机localhost容器映射到宿主机
端口5432默认端口
数据库postgres初始库
用户omm超级用户
密码你设置的 GS_PASSWORD复杂度要够

如果你在 Windows 上用 DBeaver,驱动下载可能会慢,建议提前配好代理或者手动下载 PG 驱动 jar 包。连上之后先跑一句SELECT version();确认版本,再跑\l看数据库列表。这一步看着简单,但很多人卡在密码复杂度或者端口占用上,血泪经验就是:起容器之前先netstat -ano | grep 5432确认端口没被占。

3. DDL 建表:从 ER 图到 openGauss 物理表

3.1 数据类型选型与约束定义

openGauss 的数据类型跟 PostgreSQL 基本一致,常用的有INTEGER、BIGINT、VARCHAR(n)、TEXT、NUMERIC(p,s)、DATE、TIMESTAMP。跟 MySQL 最大的区别在于:没有TINYINT,用SMALLINT代替;没有DATETIME,用TIMESTAMP;自增主键用SERIAL或者GENERATED BY DEFAULT AS IDENTITY。我一般推荐用IDENTITY,因为它是 SQL 标准写法,迁移到其他库也通用。

约束方面,PRIMARY KEY、FOREIGN KEY、UNIQUE、NOT NULL、CHECK都支持。外键的级联行为要显式写ON DELETE CASCADE或ON DELETE RESTRICT,默认是NO ACTION,跟 MySQL 的默认行为不一样,这点容易踩坑。

下面是一个学生选课系统的建表脚本,包含三张表:学生、课程、选课记录。

-- 创建学生表 CREATE TABLE student ( student_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, student_name VARCHAR(50) NOT NULL, gender CHAR(1) CHECK (gender IN ('M', 'F')), birth_date DATE, major VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 创建课程表 CREATE TABLE course ( course_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, course_name VARCHAR(100) NOT NULL, credit NUMERIC(3,1) CHECK (credit > 0 AND credit <= 10), teacher VARCHAR(50) ); -- 创建选课表,带外键 CREATE TABLE enrollment ( enroll_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, student_id INTEGER NOT NULL, course_id INTEGER NOT NULL, score NUMERIC(5,2) CHECK (score >= 0 AND score <= 100), enroll_date DATE DEFAULT CURRENT_DATE, CONSTRAINT fk_student FOREIGN KEY (student_id) REFERENCES student(student_id) ON DELETE CASCADE, CONSTRAINT fk_course FOREIGN KEY (course_id) REFERENCES course(course_id) ON DELETE RESTRICT, CONSTRAINT uk_stu_course UNIQUE (student_id, course_id) );

逻辑说明:GENERATED BY DEFAULT AS IDENTITY让主键自动递增,插入时可以不写这个字段。CHECK约束在插入数据时就会校验,比如性别只能是 M 或 F,学分必须在 0 到 10 之间。外键ON DELETE CASCADE表示删除学生时,他的选课记录也跟着删;ON DELETE RESTRICT表示如果课程还有人选,就不允许删课程。UNIQUE (student_id, course_id)防止同一个学生重复选同一门课。参数上,NUMERIC(3,1)表示总共 3 位数字,其中 1 位小数,所以最大是 99.9,够表示学分了。

3.2 修改表结构与索引创建

建完表之后,作业里经常要求你改字段、加索引。openGauss 的ALTER TABLE语法跟 PG 一致,但要注意:加列的时候如果指定NOT NULL,必须同时给DEFAULT值,否则已有数据行会报错。加索引用CREATE INDEX,唯一索引用CREATE UNIQUE INDEX。

-- 给学生表的专业字段加索引 CREATE INDEX idx_student_major ON student(major); -- 给选课表的成绩字段加索引,方便按分数段查询 CREATE INDEX idx_enrollment_score ON enrollment(score); -- 修改课程表,增加一个课程描述字段 ALTER TABLE course ADD COLUMN description TEXT DEFAULT '暂无描述'; -- 修改学生表,把专业字段长度扩到 150 ALTER TABLE student ALTER COLUMN major TYPE VARCHAR(150);

索引不是越多越好,student表数据量小的时候,加索引反而拖慢插入。我一般只在经常出现在WHERE和JOIN条件里的字段上加索引。ALTER COLUMN TYPE在数据量大时会锁表,作业环境数据少无所谓,生产环境要谨慎。另外 openGauss 支持列存表,语法是CREATE TABLE ... WITH (ORIENTATION=COLUMN),适合分析型场景,但上机作业一般用行存就够了。

4. DML 与查询:把数据真正跑起来

4.1 增删改查的标准写法与批量插入

DML 就是INSERT、UPDATE、DELETE、SELECT。openGauss 的INSERT支持多行插入,也支持INSERT ... SELECT。批量插入的时候,用一条INSERT带多个VALUES比多条单行INSERT快得多,因为减少了网络往返和事务开销。

-- 插入学生数据 INSERT INTO student (student_name, gender, birth_date, major) VALUES ('张三', 'M', '2003-05-12', '软件工程'), ('李四', 'F', '2003-08-20', '计算机科学'), ('王五', 'M', '2002-11-03', '软件工程'), ('赵六', 'F', '2003-01-15', '信息安全'); -- 插入课程数据 INSERT INTO course (course_name, credit, teacher) VALUES ('数据库原理', 3.0, '刘老师'), ('操作系统', 4.0, '陈老师'), ('计算机网络', 3.5, '孙老师'); -- 插入选课记录 INSERT INTO enrollment (student_id, course_id, score) VALUES (1, 1, 88.5), (1, 2, 92.0), (2, 1, 76.0), (3, 1, 85.0), (3, 3, 90.5), (4, 2, 81.0); -- 更新成绩 UPDATE enrollment SET score = 95.0 WHERE student_id = 1 AND course_id = 2; -- 删除一条选课记录 DELETE FROM enrollment WHERE enroll_id = 6;

逻辑说明:插入时student_id和course_id是自增的,所以不用写,数据库自动分配。UPDATE和DELETE一定要带WHERE,否则全表更新或删除,这是新手最容易犯的错。openGauss 默认开启事务,每条 SQL 自动提交,如果你要批量操作,建议显式BEGIN和COMMIT。

4.2 多表连接与聚合查询

作业报告里少不了统计类查询,比如「每个学生的选课门数和平均分」「每门课的最高分和最低分」。这时候就要用JOIN和GROUP BY。

-- 查询每个学生的选课门数和平均分 SELECT s.student_name, COUNT(e.course_id) AS course_count, ROUND(AVG(e.score), 2) AS avg_score FROM student s LEFT JOIN enrollment e ON s.student_id = e.student_id GROUP BY s.student_name ORDER BY avg_score DESC NULLS LAST; -- 查询每门课程的最高分、最低分和选课人数 SELECT c.course_name, MAX(e.score) AS max_score, MIN(e.score) AS min_score, COUNT(e.student_id) AS student_count FROM course c JOIN enrollment e ON c.course_id = e.course_id GROUP BY c.course_name HAVING COUNT(e.student_id) >= 2; -- 子查询:查询平均分高于全体平均分的学生 SELECT student_name FROM student WHERE student_id IN ( SELECT student_id FROM enrollment GROUP BY student_id HAVING AVG(score) > (SELECT AVG(score) FROM enrollment) );

LEFT JOIN保证没有选课的学生也会出现在结果里,COUNT会返回 0。ORDER BY ... NULLS LAST是 PG 系特有的,把空值排最后。HAVING是对分组后的结果过滤,跟WHERE的区别在于WHERE在分组前过滤行,HAVING在分组后过滤组。子查询里先算出全体平均分,再筛出高于平均分的学生。这些查询在作业报告里通常要求你贴出结果截图和 SQL 语句,所以写的时候注意格式对齐。

4.3 窗口函数与慢 SQL 优化初探

openGauss 支持窗口函数,做排名、累计、同比环比很方便。比如给每个学生的成绩按课程排名:

-- 按课程分组,给成绩排名 SELECT s.student_name, c.course_name, e.score, RANK() OVER (PARTITION BY e.course_id ORDER BY e.score DESC) AS rank_in_course FROM enrollment e JOIN student s ON e.student_id = s.student_id JOIN course c ON e.course_id = c.course_id;

PARTITION BY按课程分组,ORDER BY score DESC按成绩降序,RANK()给出排名,成绩相同排名并列。窗口函数不会减少行数,跟GROUP BY有本质区别。

慢 SQL 优化方面,openGauss 提供了EXPLAIN和EXPLAIN ANALYZE。在 SQL 前面加EXPLAIN可以看到执行计划,看有没有走索引、有没有全表扫描。如果看到Seq Scan而且表很大,就要考虑加索引。EXPLAIN ANALYZE会实际执行并返回耗时,适合在测试环境用,生产环境慎用,因为会真跑一遍。

-- 查看执行计划 EXPLAIN SELECT * FROM enrollment WHERE score > 80; -- 查看实际执行时间和行数 EXPLAIN ANALYZE SELECT * FROM enrollment WHERE score > 80;

如果EXPLAIN输出里出现Seq Scan on enrollment,说明没走索引。这时候可以检查idx_enrollment_score是否存在,或者查询条件是否用了函数导致索引失效,比如WHERE score + 0 > 80就不会走索引。

5. 存储过程与事务:作业里的加分项

5.1 openGauss 存储过程语法与调试

openGauss 支持存储过程,语法是 PL/pgSQL 风格。跟 MySQL 的存储过程比,openGauss 的CREATE PROCEDURE不需要DELIMITER换分隔符,直接写就行。下面是一个根据学生 ID 和课程 ID 更新成绩的存储过程:

CREATE OR REPLACE PROCEDURE update_score( p_student_id IN INTEGER, p_course_id IN INTEGER, p_score IN NUMERIC ) AS $$ BEGIN -- 校验成绩范围 IF p_score < 0 OR p_score > 100 THEN RAISE EXCEPTION '成绩必须在 0 到 100 之间'; END IF; -- 更新成绩 UPDATE enrollment SET score = p_score WHERE student_id = p_student_id AND course_id = p_course_id; -- 如果没有匹配行,抛出异常 IF NOT FOUND THEN RAISE EXCEPTION '未找到学生 % 的课程 % 选课记录', p_student_id, p_course_id; END IF; RAISE NOTICE '更新成功'; END; $$ LANGUAGE plpgsql; -- 调用存储过程 CALL update_score(1, 1, 91.0);

逻辑说明:IN表示入参,RAISE EXCEPTION抛异常并回滚,RAISE NOTICE打印提示信息。NOT FOUND是 PL/pgSQL 的内置变量,上一条 SQL 没影响任何行时为真。$$是美元引用,用来包裹过程体,避免单引号转义。调试的时候可以用RAISE NOTICE输出中间变量,openGauss 的 gsql 会直接打印到控制台。

5.2 事务控制与并发场景

事务用BEGIN、COMMIT、ROLLBACK控制。openGauss 默认是读已提交隔离级别,跟 PostgreSQL 一样。作业里经常要求模拟转账场景,验证事务的原子性。

-- 开启事务 BEGIN; -- 从学生 1 的选课记录里扣分(模拟转出) UPDATE enrollment SET score = score - 5 WHERE student_id = 1 AND course_id = 1; -- 给学生 2 的选课记录加分(模拟转入) UPDATE enrollment SET score = score + 5 WHERE student_id = 2 AND course_id = 1; -- 检查学生 2 的成绩是否超过 100 -- 如果超过,回滚 -- 这里假设业务逻辑在应用层判断,SQL 层直接提交 COMMIT;

如果中间任何一步失败,执行ROLLBACK就能撤销所有未提交的修改。openGauss 支持保存点SAVEPOINT,可以在事务内部分回滚。并发场景下,SELECT ... FOR UPDATE可以锁行,防止其他事务修改。但要注意死锁,两个事务互相等对方释放锁就会死锁,openGauss 会自动检测并回滚其中一个事务,报错信息里会提示deadlock detected。

6. 避坑与排查:上机作业里最容易翻车的 5 个点

6.1 自增主键报错:AUTO_INCREMENT不存在

现象:建表时写id INT AUTO_INCREMENT PRIMARY KEY,openGauss 报错syntax error at or near "AUTO_INCREMENT"。

原因:openGauss 不支持 MySQL 的AUTO_INCREMENT关键字,它用的是SERIAL或IDENTITY。

解决:把AUTO_INCREMENT改成GENERATED BY DEFAULT AS IDENTITY,或者用SERIAL。如果表已经建好了,用ALTER TABLE加IDENTITY属性。

6.2 密码复杂度不够导致容器起不来

现象:docker run之后容器秒退,docker logs看到password must contain at least 8 characters, including uppercase, lowercase, digit and special character。

原因:openGauss 强制密码复杂度,GS_PASSWORD太简单。

解决:密码至少 8 位,包含大小写字母、数字和特殊字符,比如Enmo@123。改完重新起容器。

6.3 外键约束导致删数据失败

现象:DELETE FROM course WHERE course_id = 1;报错update or delete on table "course" violates foreign key constraint。

原因:enrollment表里有引用course_id = 1的记录,外键约束阻止删除。

解决:先删子表记录,或者把外键改成ON DELETE CASCADE。如果不想改表结构,就先DELETE FROM enrollment WHERE course_id = 1;再删课程。

6.4 索引没生效,查询还是慢

现象:明明加了索引,EXPLAIN还是显示Seq Scan。

原因:查询条件里对索引列用了函数或类型转换,比如WHERE score::text > '80',或者WHERE score + 0 > 80,导致索引失效。

解决:把函数移到等号右边,或者建表达式索引。比如CREATE INDEX idx_score_text ON enrollment((score::text));。另外,如果表数据量太小,优化器可能觉得全表扫描更快,这是正常的。

6.5 存储过程里NOT FOUND不生效

现象:存储过程里UPDATE没匹配到行,但NOT FOUND没触发异常。

原因:NOT FOUND只对最近一条SELECT INTO、UPDATE、DELETE、INSERT生效,如果中间夹了其他语句,比如RAISE NOTICE,NOT FOUND会被重置。

解决:把IF NOT FOUND紧跟在UPDATE后面,中间不要插其他语句。或者用GET DIAGNOSTICS row_count = ROW_COUNT;获取影响行数,再判断。

7. 进阶技巧:用 gsql 元命令和系统表快速自查

上机作业做到后面,老师往往会要求你贴出表结构、索引列表、约束信息。用 gsql 的元命令比写 SQL 查系统表快得多。\d看表结构,\d+看更详细的信息包括索引和约束,\di看索引列表,\dt看所有表,\l看数据库列表,\du看用户列表。这些命令在 gsql 里直接敲,不用分号。

-- 查看 student 表的完整定义 \d+ student -- 查看所有索引 \di -- 查看所有表 \dt -- 查看当前数据库的所有 schema \dn

如果你要写脚本自动导出表结构,可以查information_schema和pg_catalog。比如查某张表的所有列:

SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = 'student' ORDER BY ordinal_position;

查某张表的所有约束:

SELECT conname, contype, pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = 'student'::regclass;

contype里p是主键,f是外键,u是唯一约束,c是检查约束。pg_get_constraintdef把约束定义还原成 SQL 文本,直接贴到报告里就行。

还有一个实用技巧:用\copy导出查询结果到 CSV,比COPY命令更适合客户端。

-- 导出选课成绩到 CSV \copy (SELECT s.student_name, c.course_name, e.score FROM enrollment e JOIN student s ON e.student_id = s.student_id JOIN course c ON e.course_id = c.course_id) TO '/tmp/scores.csv' WITH CSV HEADER;

\copy是 gsql 客户端命令,文件路径是客户端所在机器的路径,不是服务器路径。WITH CSV HEADER表示带表头。导出的 CSV 可以直接用 Excel 打开,贴到作业报告里。

我自己的习惯是:每次上机之前先把\d+的输出存一份,建完表、加完索引、写完存储过程之后各存一份,对比一下就知道自己改了哪些东西。作业报告里要求贴表结构的时候,直接复制粘贴,不用手敲。另外,openGauss 的gs_dump可以导出整个数据库的 SQL 脚本,命令是gs_dump -U omm -d postgres -f /tmp/backup.sql,导出的脚本里包含所有 DDL 和 DML,适合交作业前做全量备份。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询