简介:面向重庆大学数据库课程学习者与备考学生,整合了理论复习、实验操作与考试演练所需的完整学习资料,覆盖数据库基础、关系模型、SQL、查询优化及事务处理等核心内容。资源包共185个文件,约210.48MB,以png课件截图、ppt/pptx授课幻灯片、pdf讲义、doc/docx文档笔记与试题、java示例代码等类型为主,并辅以实验指导与说明文档,便于按需查阅。已有68人学习下载,适合正在复习数据库课程、准备期末考核或希望系统梳理知识体系的学生使用。资料中不仅包含复习重点、课堂笔记和数据库算法解析,还提供简答题型总结、历年考试试题及答案标注,以及实验报告参考,可帮助读者快速抓住考点、理解难点并检验学习成效。
1. 重庆大学数据库.zip:当交付物是压缩包时,先想清楚里面装的是什么
「重庆大学数据库.zip」这类文件名,在高校和课题组场景里几乎每天都会出现:上一届的课程设计交付、某个系统的数据归档,也可能是导师顺手扔给你的历史数据。你把它拿下来,目的是要还原成一个能查、能写、能跑 API 的数据库,而不是欣赏解压动画。这种包最常见的内容是 .sql 备份加几张 CSV,偶尔混进 MySQL 的物理文件目录或 SQLite 的 .db 单文件,也有一小部分是课件 PDF 加一段残缺脚本的「气氛组」。适合读这篇的,是接过学长项目的在校生、接手历史数据交付的团队新人,以及想用离线数据集复现结论的工程师。先立个规矩:别双击解压、别双击导入,包外的清单和包内的类型判断,决定你后面是十分钟收工还是折腾整个下午。
2. 先验货再落地:从 zip 清单到安全解压的一整套操作
2.1 用 unzip -l 看清单,而不是急着解压
大多数人在 Windows 上会直接双击打开 zip,点进某个目录发现一个几十 MB 的 db.sql,顺手就把鼠标挪到导入按钮上。我建议第一步别解压,先跑一条unzip -l,把包内清单读出来。对 zip 来说,-l只读取中央目录,不解压任何文件内容,几百 MB 的包也是秒级返回,快得让你感觉像在作弊。
# 读取 zip 内文件清单,先看前面的 80 行,重点看 Length 列 unzip -l 重庆大学数据库.zip | head -80 # 清单较长时统计文件数量 unzip -l 重庆大学数据库.zip | wc -l # 查看清单末尾的总解压体积 unzip -l 重庆大学数据库.zip | tail -5unzip -l输出的每一行有 Length、Date、Time、Name 几个字段,Length 列是按原始大小算的,先把它和df -h里目标盘的可用空间对比,能直接筛掉「解压到一半磁盘爆掉」这种事故。另一个容易被忽略的信息是 Name 列里有没有多个同名文件,或者出现../开头、绝对路径开头的条目。命令行里先做人工初筛,后面 2.3 会给一个脚本专门处理这些异常。
Windows 上不方便跑 unzip 的话,用 7-Zip 打开压缩包,在「文件 -> 查看信息」里同样能看到总解压体积和文件数。这一步花不了十秒钟,但能帮你躲开最蠢的一种失败。
顺便说一句,清单里的文件命名其实能透露不少信息:如果看到backup_2024.sql、course_data.csv这种规整命名,包的主人大概率是认真归档过的;如果看到新建 文本文档.sql或者一串乱码文件名,后面就得做好手工处理的准备。unzip -l只能证明 zip 打开正常,包里每个文件有没有在传输过程中损坏,还得用逐文件 CRC-32 比对来确认,这个在 2.3 里一并解决。
2.2 包内三种常见结构,决定了后续导入路线
看完清单,下一步是给包内的内容分个类。压缩包里装的是数据库,但「数据库」这四个字在交付场景里至少对应四种不同的物理形态,处理方式完全不一样。
| 包内特征 | 实际类型 | 导入路线 |
|---|---|---|
单个 db.sql,头部含-- MySQL dump | mysqldump 逻辑备份 | mysql 命令直接灌 |
| 多个 .sql 加同名 .csv | DDL 脚本加数据文件 | 先建表,再 LOAD DATA |
| 目录里散着 .frm / .ibd / .opt | MySQL 物理文件 | 版本严格一致后 IMPORT TABLESPACE |
| 单个 .db 或 .sqlite 文件 | SQLite 单文件库 | 只读挂载即可 |
| .bin / .json 成对出现 | 向量数据库导出文件 | 走对应引擎的 native 导入接口 |
注意:.sql扩展名并不可信。我见过很多次交付包里叫data.sql的文件实际上是 gzip 压缩的文本,或者干脆是 SQLite 的 dump,所以第二步必须拿真实内容说话,别拿文件名赌。
# 用 file 读文件真实类型,文本型 dump 和二进制 dump 一眼区分 file db.sql # 如果输出里有 gzip compressed data,先解一层再往下走 gzip -d db.sql.gzfile命令的输出会把 db.sql 识别为ASCII text、Unicode text或gzip compressed data。如果识别出来是压缩格式,说明导入前要先做一次格式转换,而不是傻乎乎地把二进制内容喂给 mysql 客户端。特别是 pg_dump 的 custom 格式,file输出会带PostgreSQL custom database dump字样,这时就该用 pg_restore 而不是 psql。这一步能避开 90% 的「命令选错工具」问题。
碰到 .db 或 .sqlite 文件时,先别急着导入 MySQL。SQLite 本身就是一个完整数据库,直接sqlite3 course.db ".tables"看一眼表结构,大多数情况可以直接用,不需要做无谓的迁移。只有在业务要求统一走 MySQL 的时候,才考虑用sqlite3 db.db ".dump"导出成 SQL 再转换。
MySQL 物理文件目录是最麻烦的一种。.frm、.ibd、.opt是 InnoDB 的磁盘文件,直接拷贝到另一台机器的 data 目录通常起不来,它要求源和目标实例的 MySQL 小版本严格一致,而且必须都是 InnoDB file-per-table 模式。如果不是这两个条件都满足,我一般会劝你放弃物理文件,找原始环境做一次 mysqldump 再走逻辑导入,这条路虽然绕,但至少可控。
2.3 手写一个安全解压脚本:编码、CRC 和路径穿越一次查完
单条命令做不了的事,交给 Python 的 zipfile 库。我一般会用下面的脚本做三步:先跑 CRC 完整性校验,再检查有没有路径穿越,最后只把 .sql、.csv、.db 这类数据文件摘出来,不把整个包倒出来占地方。
import zipfile from pathlib import Path SRC = Path("重庆大学数据库.zip") OUT = Path("./package_content") OUT.mkdir(exist_ok=True) with zipfile.ZipFile(SRC) as zf: # 第一步:testzip 内置 CRC 逐文件比对,返回第一个损坏的文件名 bad = zf.testzip() if bad: raise SystemExit(f"[阻塞] 文件损坏:{bad},先回源补一份再继续") # 第二步:遍历所有条目,做路径穿越与绝对路径检查 for info in zf.infolist(): # zipfile 对非 ASCII 文件名按 cp437 解码,中文会乱码 # 先把字节取回,再按 GBK 或 UTF-8 重新解码 raw = info.filename try: real_name = raw.encode("cp437").decode("gbk") except UnicodeDecodeError: real_name = raw # 目标里出现绝对路径或 .. 跳级,直接拒绝 if real_name.startswith("/") or ".." in Path(real_name).parts: print("[跳过] 异常路径:", real_name) continue # 第三步:只摘出文本型数据文件,避免把几百 MB 附件全倒出来 if real_name.endswith((".sql", ".csv", ".db")): target = OUT / Path(real_name) target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(zf.read(info)) print("[解压]", real_name)这里几个逻辑点需要说透。testzip()是 zipfile 提供的完整性检查入口,它会逐个把文件解压到内存并比对 CRC-32 值,全部通过返回 None,遇到损坏就返回那个文件名。返回值不为空时,说明压缩包已经在传输过程中坏掉了一部分,这时候不要继续用,先去原始来源重新取包。那些声称能直接修复 zip 的小工具,成功率不高,与其赌修复,不如重新下载一次。
文件名解码是中文压缩包的经典玄学现场。zip 格式内部对非 ASCII 文件名没有强制要求,很多打包工具把中文按 GBK 编码写进去,Python 3 的 zipfile 默认按 cp437 解码,于是显示成各种奇怪字符,直接用extract()解出来的就是乱码文件名。上面的代码先把乱码字符串还原成字节,再按 GBK 解码,能恢复大多数 Windows 生态下打包的中文文件名。如果包是用 Linux 的 zip 命令打的,编码可能是 UTF-8,这时候decode("gbk")会抛异常,代码里的except就把它回退成原名了。
最后一步「只摘 .sql / .csv / .db」是刻意为之。很多交付包会给同目录塞一堆课程 PPT、实验报告,跟这次导入毫无关系,全量解压既慢又占地方。如果确实需要整包解压,把endswith判断删掉,或者直接zf.extractall(),但记得先确认磁盘空间够。
3. 把 dump 灌进 MySQL 与 PostgreSQL:命令选型、编码参数与提速配置
3.1 先分辨备份格式:mysqldump、pg_dump 还是手工脚本
在动手灌数据库之前,先用head看文件头部内容。数据库 dump 文件几乎都会在开头留下痕迹,读前三十行就能识别出来。
head -n 30 db.sql如果看到-- MySQL dump或/*!40101 SET ... */,这是 mysqldump 的产物,直接用 mysql 客户端导入。如果看到CREATE DATABASE配合USE语句,通常是手工导出的脚本,它不一定是 MySQL,也可能是 MariaDB,但导入姿势基本一致。看到-- PostgreSQL database dump就是 psql 的文本格式,得走psql -f。看到二进制头部PGDMP或file输出里带 custom dump 字样,这是 pg_dump 的 custom 格式,只能交给 pg_restore。
这里见过的最常见翻车姿势,是拿着一个 PostgreSQL 的文本 dump,用mysql < db.sql去灌,前几行能跑,到CREATE TABLE语法报错就开始怀疑人生。所以这一步不是可有可无的仪式,而是后面所有命令选型的基础。
还有一个容易误判的场景:dump 文件头部什么标记都没有,直接一串INSERT INTO。这种情况通常是数据脚本而不是完整备份,它不负责建表。导入前先确认目标库里表已经建好,否则第一条 INSERT 就会报table doesn't exist,而且报错之前你已经跑了好几分钟,白等。
3.2 MySQL 导入:三种姿势,以及必须带上的两个参数
MySQL 导入分成两种情况:dump 自带建库语句,和 dump 里只有表不含库。前者直接往服务器灌,后者要先建库再灌。我一般按下面的顺序来。
# 先创建目标库,字符集一步到位 mysql -uroot -p -e "CREATE DATABASE school_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" # 不含建库语句的 dump,导入时指定库名 mysql -uroot -p --default-character-set=utf8mb4 school_db < db.sql # dump 自带 CREATE DATABASE 时,不用给库名,直接整体灌入 mysql -uroot -p --default-character-set=utf8mb4 < db.sql # 单条 INSERT 特别大时,把客户端收发包上限调大 mysql -uroot -p --default-character-set=utf8mb4 --max-allowed-packet=1G school_db < db.sql--default-character-set=utf8mb4是必带参数,它同时影响连接层的字符串解释和服务端部分会话变量。如果没有它,连接默认可能是 latin1 或 utf8,dump 文件里的 utf8mb4 中文在导入时被错误转码,查出来就是一片问号。--max-allowed-packet=1G不是真的让客户端发 1GB 的包,而是把协议层的包上限放开,避免某条包含大文本或 BLOB 的 INSERT 在握手阶段就被拒绝。这个参数和服务端的max_allowed_packet是两回事,两者都得大于实际单句 SQL 的长度,缺一不可。
还有一种常见姿势是在 mysql 命令行客户端里用source命令导入。source db.sql和管道重定向本质差不多,但它能持续打印执行的语句进度,导入到哪一句报错也看得更清楚。不过source只能在交互式客户端里跑,脚本里不方便用。
如果目标库里已经有部分表,比如旧表只缺数据,直接导会撞主键冲突。建议先对比表结构,确认新旧表字段一致再决定是 truncate 还是续导。拿不准的时候先把旧库mysqldump一份留底,再动手不迟,这叫后悔药。
3.3 PostgreSQL 导入:psql 还是 pg_restore,按文件类型选
PostgreSQL 的导入没有 MySQL 那么随便,格式匹配比什么都重要。文本格式的 dump 文件用 psql,custom 或 directory 格式的 dump 用 pg_restore,混用会直接报错。
# 建库 createdb -U postgres school_db # 文本格式 dump,用 psql 逐句执行 psql -U postgres -d school_db -f db.sql # custom 格式或目录格式,用 pg_restore 并行恢复 pg_restore -U postgres --jobs=4 --clean --if-exists -d school_db db.dump # 带 gzip 压缩的文本 dump,先解压再管道给 psql gunzip -c db.sql.gz | psql -U postgres -d school_dbpsql -f是逐句执行的,遇到前面某条语句报错不会自动停,最后可能留下一半对象。想让它严格一点,加-v ON_ERROR_STOP=1,一旦出错就退出整个导入。pg_restore 的--jobs=4开启四个并发进程,对表间没有外键依赖的 dump 提速明显;有依赖时 pg_restore 会按依赖顺序自动调整,所以可以放心开。--clean --if-exists的作用是清理目标库里同名对象,避免重复导入时报错。
另一个值得养成的习惯是给 pg_restore 加--no-owner。dump 文件里记录的属主账号在目标环境不一定存在,不带这个参数会报role does not exist,导入直接中断。加上之后,所有对象归当前连接用户,后面再按业务需求授权。PostgreSQL 的 custom 格式只认PGDMP魔数,你在 Windows 上把它改名为.sql也不会变成文本,file命令一查就露馅。
3.4 导入慢的四个开关:临时参数提速,完事记得恢复原值
导入几百 MB 的 dump,默认配置跑起来确实煎熬。问题通常不在表结构,而在每次提交事务时 MySQL 都在等日志刷盘。导入阶段可以临时调整几个参数,但记住这是施工状态,不是生产状态。
| 参数 | 默认值 | 导入时建议 | 说明 |
|---|---|---|---|
| innodb_flush_log_at_trx_commit | 1 | 2 | 每次提交只写 OS 缓存不刷盘,提速明显,崩溃最多丢最近事务 |
| sync_binlog | 1 | 1000 | binlog 攒批刷盘,减少磁盘 IO 次数 |
| foreign_key_checks | 1 | 0 | 跳过外键检查,导入完再开 |
| unique_checks | 1 | 0 | 跳过唯一索引检查,前提是数据源可信 |
| max_allowed_packet | 64M | 1G | 避免大事务直接失败 |
| innodb_buffer_pool_size | 128M | 物理内存的 60% 左右 | 放大页缓存,建索引更快 |
# MySQL 全局参数,用 zip 方式装起来的实例也能这么改,跟安装方式无关 mysql -uroot -p -e " SET GLOBAL innodb_flush_log_at_trx_commit=2; SET GLOBAL sync_binlog=1000; SET GLOBAL foreign_key_checks=OFF; SET GLOBAL unique_checks=OFF; SET GLOBAL innodb_buffer_pool_size=$((512*1024*1024)); "PostgreSQL 这边同样有施工参数,常见做法是导入前把maintenance_work_mem调到 1GB,把fsync暂时关掉,导入完成再恢复。用ALTER SYSTEM写进配置,再SELECT pg_reload_conf()让它生效。
psql -U postgres -c "ALTER SYSTEM SET maintenance_work_mem='1GB';" psql -U postgres -c "SELECT pg_reload_conf();" # 导入完成后恢复 psql -U postgres -c "ALTER SYSTEM SET maintenance_work_mem='64MB';" psql -U postgres -c "SELECT pg_reload_conf();"foreign_key_checks和unique_checks这类开关有个前提:你得相信源数据本身是干净的。如果数据里有外键断裂,关掉检查导入只是把问题留到查询时爆雷。所以关开关之前,先确认这个包是正式交付的库,而不是某个从生产库直接拷的裸 dump。这句话听起来像废话,但高校交付场景里,裸 dump 的比例比你想的高得多。
4. 导入完不算玩完:三层数据体检和脏数据处理的实操顺序
4.1 三层校验:行数、表结构、外键完整性
导入成功之后,库能查不代表数据对。我每次都会做三层体检:第一层数行数,第二层对表结构,第三层查外键孤儿。这三层分别验证「量的完整」「形的完整」「关系的完整」。
-- 第一层:核心表行数核对,和包内 README 或源端统计对比 SELECT COUNT(*) AS total_cnt FROM students; -- 第二层:列出所有表名和估算行数,快速看有没有表是空的 SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema = 'school_db' ORDER BY table_name; -- 第三层:外键断裂检查,找出子表里没有对应父表记录的行 SELECT s.id AS score_id, s.stu_id FROM scores s LEFT JOIN students st ON s.stu_id = st.id WHERE st.id IS NULL LIMIT 50;第一层的COUNT(*)是精确统计,注意别和information_schema.tables里的table_rows混为一谈。table_rows对 InnoDB 是估算值,可能偏差很大,但用来快速发现「某张表完全没数据」还是好用的。第三层的 LEFT JOIN 是体检外键最直接的方式:子表留下一行 NULL 就能说明父表缺行。除非业务设计本来就允许空外键,否则这笔记录必须处理。
表结构核对在 MySQL 里可以这样快速做:源端跑mysqldump -d只导 DDL,目标端也跑一次,然后diff两个文件。差异集中在字段类型、默认值、索引名上,一眼就能看出导入端有没有因为版本差异改了表结构。
mysqldump -uroot -p -d school_db > schema_after.sql diff schema_before.sql schema_after.sqldiff 输出的每一行都值得看一眼,特别是int(11)变int这种。它不影响数据,但会影响下游 ORM 对字段类型的判断。真正的坑在于datetime默认值、varchar长度这类差异,可能导致应用层写入报错。
4.2 三个老问题:乱码残留、自增错位、外键孤儿
跑完体检,最常撞上的是三个老问题,而且它们往往是同一批数据带来的。
乱码残留。导入时参数没带对,库里就会出现�或锟斤拷这种经典形态。检测并不难:
-- 经典乱码形态:有效 UTF-8 文本里很少出现这种字符序列 SELECT * FROM students WHERE name LIKE '%�%' OR name LIKE '%锟斤拷%' LIMIT 20;如果确认文件是 GBK 而库是 utf8mb4,最省事的修法是把文件整体转码后重导:iconv -f GBK -t UTF-8 db.sql > db_utf8.sql。不要在库里做替换,字段级替换会留下半吊子数据,后面越查越玄学。
自增错位。源库删过数据或者手工导入过,新库的自增 ID 可能已经用到很大,也可能比现有数据小,直接导致后续插入主键冲突。修复很简单:
-- 先看当前自增位置,再一次性拨正 ALTER TABLE students AUTO_INCREMENT = 10001;外键孤儿。前面体检查到的那批 LEFT JOIN 结果为 NULL 的记录就是孤儿。处理方向只有两个:要么把缺失的父表记录补出来,要么把孤儿子表记录删掉。无论选哪个,先CREATE TABLE scores_backup AS SELECT * FROM scores留一份备份,再动手,避免误删后找不回原始数据。
4.3 收尾四件事:字符集、时区、权限、归档
体检全过,还有四件小事在交付前做掉,否则下一个接手的人大概率回来找你。
字符集统一确认,主要看服务端、连接、表三级是否都落到 utf8mb4:
SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'character_set_connection'; SHOW VARIABLES LIKE 'collation_server';时区要在库里落盘,不要只依赖应用层。MySQL 是SET time_zone = '+08:00',PostgreSQL 建议用具名写法,ALTER DATABASE school_db SET timezone TO 'Asia/Shanghai'。没有这一步,生产库里的NOW()和你查数据时的直觉永远差着一截。
权限收敛,这是老生常谈但经常被跳过:给下游业务账号只授 SELECT 或增删改查的最小权限,不要拿 root 去对接一个刚导入的数据。哪怕只是课程设计,也把 root 留在自己手里,给别人用单独建账号。
-- 只读账号示例,按实际表名调整 CREATE USER 'reader'@'%' IDENTIFIED BY 'readonly_pass'; GRANT SELECT ON school_db.* TO 'reader'@'%'; FLUSH PRIVILEGES;归档是这个流程的最后一环。把原始 dump 压缩归档成db_YYYYMMDD.sql.gz,并在旁边写一行来源说明:从哪个 zip 来的、用的什么命令导入、导入前改过哪些参数。这份说明对下一个人来说,比任何注释都值钱。
5. 避坑手记:解压与导入数据库路上最常翻车的 5 个问题
我把解压、导入这条路上最容易翻车的五个问题按「现象、原因、解决」记在这里。每一条都是实际处理过至少一次的,不是凭感觉写的。
5.1 现象:unzip 解压到一半报 bad CRC-32 或 unexpected end of file
解压工具突然罢工,控制台滚出一行bad CRC-32然后整个解压中断。原因多半是压缩包在网盘、即时通讯工具或 U 盘拷贝过程中被截断了,zip 的中央目录还在,但某个文件的压缩数据已经不完整。个别情况下是解压软件对中文文件名编码兼容性差,报错位置刚好落在中文目录。
解决:先用unzip -T 重庆大学数据库.zip做一次整包测试,它会逐文件解压到内存校验 CRC-32,输出 OK 或坏文件名。如果坏的是某一个数据文件,用unzip -o 重庆大学数据库.zip 坏文件名 -d 输出目录单独把完好文件摘出来;如果坏在中央目录本身,unzip -t连跑都跑不起来,这是整个包废了,唯一的后悔药就是回源重新下载,任何声称能修复 zip 的第三方工具都别信。
5.2 现象:导入到一半,客户端报 ERROR 2006 (HY000) MySQL server has gone away
导入速度其实正常,但跑了几万行之后突然断掉,报 MySQL server has gone away。原因几乎都是某一条 INSERT 语句太大,超过了服务端或客户端的max_allowed_packet,导致连接被服务端主动断开。也有小概率是wait_timeout太短,正好碰上一条执行很慢的语句。
解决:先确认当前上限,然后临时调大再重导。
mysql -uroot -p -e "SHOW VARIABLES LIKE 'max_allowed_packet';" mysql -uroot -p -e "SET GLOBAL max_allowed_packet=1G;" mysql -uroot -p --max-allowed-packet=1G school_db < db.sql注意SET GLOBAL只对之后的新连接生效,正在跑的那些连接不会有变化,所以要先断掉旧连接再重新导入。另一个隐蔽点是 dump 文件里如果带LOCK TABLES,导入时对表的占用会顶到锁等待超时,报错信息也是 gone away 的变体,此时看一眼SHOW PROCESSLIST,确认是否有锁堆积比盲目加大参数更靠谱。
5.3 现象:导入后中文全变成问号或 æä½ 这种乱码
查出来的中文不是???就是æä½è¿之类的存活乱码。这三件事通常是同一场事故:dump 文件本身是 GBK,表定义是 utf8mb4,客户端的连接字符集又不一样。乱码看起来玄学,实际只有三个位置需要确认:文件本身编码、连接层字符集、表字段字符集。三者都统一才可能正常。
解决:先看文件实际编码再决定重导参数。
# 第一条命令就能确认文件真实编码 file -i db.sql # 如果文件是 GBK,用 iconv 转成 utf8 再导入 iconv -f GBK -t UTF-8 db.sql > db_utf8.sql # MySQL 侧连接层指定 utf8mb4 mysql -uroot -p --default-character-set=utf8mb4 school_db < db_utf8.sqlPostgreSQL 这边的做法类似,导入前设置PGCLIENTENCODING=UTF8,再执行psql -f。在库里做字符串替换是下策,因为替换规则很难覆盖所有乱码形态;重导虽然多花几分钟,但结果可控。
5.4 现象:表明明建好了,查询却报 Table 'xx.xx' doesn't exist
导入过程没有任何报错,但业务查询一跑就报表不存在。原因十有八九是大小写敏感度不一致:Windows 上导出的库名、表名带大小写,Linux 上的 MySQL 默认lower_case_table_names=0区分大小写,于是students和Students被当成两张不同的表。
解决:先确认两边配置,再决定要不要统一表名。
mysql -uroot -p -e "SHOW VARIABLES LIKE 'lower_case_table_names';"lower_case_table_names这个参数在 Linux 上改起来很麻烦,改成 1 需要重启实例,而且已有库表可能有兼容性问题。务实做法是把 dump 文件里的库名、表名统一改写为小写,重新导一遍;或者在应用层把查询 SQL 里的表名改成和库一致。这个坑最气人的地方是它不在导入时报,偏偏在验证查询时报,所以我把它放在体检之后提。
5.5 现象:解压到一半磁盘满了,zip 停止且已解压文件是残缺的
zip 本体才 300MB,解压出来 2GB,结果目标盘只有 1.5GB。解压器在写某个文件时碰到磁盘满,直接退出,已解压出来的文件大小停在半路上,后面再补解压只会更乱。
解决:解压之前看总规模,解压失败后清掉残缺文件再重来。
# 解压前看总解压体积,和 df 剩余空间对比 unzip -l 重庆大学数据库.zip | tail -5 df -h /目标盘 # 失败后先把那些大小明显偏小的 sql 捡出来删掉 find /目标盘 -name "*.sql" -size -100k -deletezip 的解压不是事务性的,中断就是中断,没有后悔药。用前面 2.3 的脚本只摘数据文件,通常能从源头避开这一节,因为脚本不会把附件和 PPT 全倒出来。万一非全量解压不可,可以先只解 .sql,再单独解其他大文件,分步走总比一次爆盘强。
6. 从一次性导入到可复现交付:一份启动脚本和三分钟验收技巧
如果这套「重庆大学数据库.zip」不是只导一次,而是过两个月又要再导一次,甚至要交给下一个人接手,就该把流程固化成脚本。我给一个最小可用的启动框架:
#!/usr/bin/env bash set -euo pipefail ZIP="${1:-重庆大学数据库.zip}" DB="school_db" # 1. 先记账,列出清单再决定不做什么 unzip -l "$ZIP" > /tmp/db_list.txt python3 unzip_safe.py # 2. 建库导入,字符集写进 DDL,不依赖环境变量 mysql -uroot -p <<SQL CREATE DATABASE IF NOT EXISTS ${DB} DEFAULT CHARACTER SET utf8mb4; SQL mysql -uroot -p --default-character-set=utf8mb4 "${DB}" < db.sql # 3. 三分钟验收:总量 + 外键孤儿 + 空表,一条 SQL 全查 mysql -uroot -p "${DB}" <<SQL SELECT "总学生数" AS kpi, COUNT(*) FROM students UNION ALL SELECT "孤儿分数记录", COUNT(*) FROM scores s LEFT JOIN students st ON s.stu_id=st.id WHERE st.id IS NULL UNION ALL SELECT "空表数", COUNT(*) FROM information_schema.tables WHERE table_schema='${DB}' AND table_rows=0; SQL # 4. 导入日志留档 echo "$(date '+%F %T') ${DB} 导入完成, 来源 ${ZIP}" >> import.log脚本里的set -euo pipefail是硬性要求:任何一个环节失败,脚本立刻退出,不会留下一个状态未知的库让你事后猜。验收 SQL 特意只放三个 KPI——总量、孤儿数、空表数,分别对应量、关系、结构,三分钟内能看完,适合在导入后立刻跑。
我的习惯是把这份脚本和 import.log 一起放进项目仓库,下次有人问「这个库哪来的」时,一行 log 就讲完了。以前我也不写流程,直到一次把同一个 zip 在不同环境导了三遍,三遍结果都不一致,才明白这个动作到底省了多少事。希望这篇里的流程能帮到你,至少不会在第一步栽跟头。
本文还有配套的精品资源,点击获取