ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大连理工软件数据库openGauss上机作业实战:从建表到存储过程避坑指南

大连理工软件数据库openGauss上机作业实战:从建表到存储过程避坑指南 简介这份资源是大连理工大学软件学院数据库系统课程的上机作业报告基于华为 OpenGauss 数据库管理系统编写面向正在学习数据库课程、需要完成上机实验或撰写实验报告的高校学生。报告内容覆盖数据库系统课程的核心实验模块包括 DDL 数据定义语言创建数据库、表、索引与视图、DML 数据操作语言数据插入、更新与删除、数据查询单表查询、聚合查询、多表查询、子查询与集合查询、索引操作以及事务的并发控制等并配有预备知识、实验任务与 SQL 代码及对应结果便于对照理解与复盘。资源包共 1 个 docx 文件约 1.36MB结构完整、章节清晰可直接作为实验报告模板或学习参考。目前已有 619 人学习下载适合需要系统掌握 OpenGauss 基本操作、查漏补缺或整理实验文档的软件学院学生使用。1. 从一份上机作业说起openGauss 到底要练什么很多人第一次接触大连理工软件数据库 opengauss 上机作业报告脑子里冒出来的第一个问题不是 SQL 怎么写而是「这玩意儿跟 MySQL 到底差在哪」。我当年也是这么想的结果第一次上机就翻车——照着 MySQL 的习惯写AUTO_INCREMENTopenGauss 直接报错因为人家用的是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_PASSWORDEnmo123 \ -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 (ORIENTATIONCOLUMN)适合分析型场景但上机作业一般用行存就够了。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 KEYopenGauss 报错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 位包含大小写字母、数字和特殊字符比如Enmo123。改完重新起容器。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 NOTICENOT 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适合交作业前做全量备份。希望帮到你。本文还有配套的精品资源点击获取
返回列表