从“拷文件”到“一致性恢复”:达梦数据库备份与还原入门
1. 备份到底在保护什么?
最初最容易把备份想成:
“把数据文件拷一份,坏了再拷回去。”
对文件系统级冷拷而言,这句话有时够用;对数据库却不够。数据库真正需要保护的是:
- 数据页(Data Page):表数据、索引最终落在磁盘上的页;
- 事务日志(Redo / Archive):把“改了什么”按时间顺序记下来;
- 元数据与实例身份:控制文件、
dm.ini、库的 MAGIC 等,决定实例能不能识别这套数据文件。
一次“可用的恢复”,本质是把库拉回到某个一致的状态点——要么是备份完成瞬间的一致性,要么是备份点之后、再用归档日志“滚”到的某个时间点。
可以先记这张关系图:
业务写入
│
▼
共享缓冲 / 数据页修改 ──► 刷盘到 .dbf(慢路径、异步)
│
▼
Redo 日志(在线日志)──► 归档日志(开启 ARCHIVELOG 后)
│
▼
备份集 / .bak / .dmp ←── 你真正要保管的“恢复原料”
- 逻辑备份(
dexp/dimp):导出的是对象与行数据的“可移植副本”,不依赖原库页布局。 - 物理备份(
BACKUP/dmbackup/RMAN BACKUPSET):拷的是页级/库级物理映像,恢复快,但对路径、页大小、版本更敏感。 - 归档:联机备份和“指定时间点恢复(PITR)”的地基。没有归档,很多联机能力会缺一条腿。
2. 逻辑/物理、联机/脱机、全量/增量
| 维度 | 选项 | 理解 |
|---|---|---|
| 形态 | 逻辑(dmp) / 物理(bak / 备份集) | 逻辑像“导出 Excel”;物理像“整盘快照” |
| 时机 | 联机(不停服务) / 脱机(停服务) | 联机靠归档补齐“备份过程中还在变的页”;脱机则库本身静止 |
| 粒度 | 表 / 模式 / 用户 / 全库;全量 / 增量 | 粒度越小越灵活;全量是基线,增量是差分 |
关键词:
- 覆盖还原:物理
restore table/dmrestore/ RMANRESTORE往往会覆盖目标对象或整个库文件。 - 非覆盖还原:
dimp更偏“导入”,目标对象通常要先存在(模式/用户先建好),冲突策略也更“追加式”。
3. 一切联机备份的前提:开启归档
做定时物理备份前先开归档。
联机备份时,某些数据页可能正被修改。备份进程读到的页集合,在时间上并不“同时”。数据库用归档日志补上备份窗口内的变更,才能在还原后做 RECOVER,收敛到一致点(SCN/LSN 语义上的一致性)。
步骤:
-- 1) 切到 MOUNT,才能改归档属性
ALTER DATABASE MOUNT;
-- 2) 开启归档模式
ALTER DATABASE ARCHIVELOG;
-- 3) 配置本地归档目录、单文件大小与空间上限(按环境调整)
ALTER DATABASE ADD ARCHIVELOG
'DEST=/opt/dmdbms/data/DAMENG/arch, TYPE=LOCAL, FILE_SIZE=2048, SPACE_LIMIT=51200';
-- 4) 重新 OPEN
ALTER DATABASE OPEN;
验证归档是否生效:
SELECT DECODE(ARCH_MODE,'Y','启用','N','未启用') AS "归档状态"
FROM V$DATABASE;
观察归档相关 LSN(手册常用视图):
SELECT
CUR_LSN AS "当前LSN",
FILE_LSN AS "已经刷到盘上的LSN",
FLUSH_LSN AS "准备刷到盘上的LSN",
FLUSHING_PAGES AS "正在刷盘总页数",
TOTAL_SPACE/1024/1024 AS "归档日志总空间M",
FREE_SPACE/1024/1024 AS "归档日志剩余空间M"
FROM V$RLOG;
学习提示:把
CUR_LSN想成库的“进度条”。全量备份钉住一个基线进度;增量备份记录“相对基线又前进了哪些页”;归档则记录“页变更的细粒度流水”。PITR 就是:先回到备份基线,再用归档把进度条拨到指定时刻。
归档也要做生命周期管理,否则磁盘会爆:
-- 保留最近 30 天归档(示例)
SF_ARCHIVELOG_DELETE_BEFORE_TIME(SYSDATE - 30);
4. 逻辑备份:dexp / dimp —— 初学者最友好的“对象级保险箱”
逻辑导出不要求停服务,适合:
- 迁表、迁模式、做开发库灌数;
- 只要部分对象,不需要整库物理一致快照;
- 跨环境时更在意“对象可导入”,而不是“页布局原样”。
4.1 表级
# 备份多表(联机)
./dexp userid=SYSDBA/你的密码@localhost:5236 \
file=tab.dmp log=tab.log \
tables=TEST.T1,TEST.T2 \
directory=/opt/bak/
# 还原多表(联机;手册标注:非覆盖)
./dimp userid=SYSDBA/你的密码@localhost:5236 \
file=tab.dmp log=tab.log \
tables=TEST.T1,TEST.T2 \
directory=/opt/bak/
4.2 模式级 / 跨模式 remap
# 备份模式
./dexp userid=SYSDBA/你的密码@localhost:5236 \
file=sch.dmp log=sch.log \
schemas=TEST1,TEST2 \
directory=/opt/bak/
# 还原前先建好目标模式
./dimp userid=SYSDBA/你的密码@localhost:5236 \
file=sch.dmp log=sch.log \
schemas=TEST1,TEST2 \
directory=/opt/bak/
# A 模式数据导入到 B 模式
./dimp userid=SYSDBA/你的密码@localhost:5236 \
file=sch.dmp log=sch.log \
schemas=A directory=/opt/bak/ \
remap_schema=A:B
4.3 用户级 / 全库逻辑导出
# 多用户
./dexp ... file=users.dmp log=users.log owner=TEST1,TEST2 directory=/opt/bak/
./dimp ... file=users.dmp log=users.log owner=TEST1,TEST2 directory=/opt/bak/
# 全库逻辑导出(手册标注:慎用!体积大、耗时长、恢复语义也更复杂)
./dexp ... full=y file=all_bak.dmp log=all_bak.log directory=/opt/bak/
./dimp ... full=y file=all_bak.dmp log=all_bak.log directory=/opt/bak/
底层直觉:dexp 走的是 SQL/对象字典通道,读的是“逻辑行 + DDL 信息”,不是直接 memcpy 数据文件。所以它跨字符集/部分环境迁移更灵活,但通常比物理备份慢,也不适合作为唯一的灾难恢复手段。
5. 物理备份之一:SQL 层 BACKUP / RESTORE
5.1 单表物理备份(联机)
-- 压缩备份单表
BACKUP TABLE TEST.T1
TO table_bak
BAKFILE '/opt/TEST_T1.bak'
COMPRESSED;
-- 还原
RESTORE TABLE FROM '/opt/TEST_T1.bak';
加密示例:
BACKUP TABLE TEST.T1
TO table_bak
BAKFILE '/opt/TEST_T1.bak'
IDENTIFIED BY admin1234
WITH ENCRYPTION 2
COMPRESSED;
RESTORE TABLE FROM '/opt/TEST_T1.bak' IDENTIFIED BY admin1234;
5.2 全库物理备份(联机 SQL)
BACKUP DATABASE FULL
TO all_bak
BAKFILE '/opt/all_bak.bak'
COMPRESSED;
5.3 脱机工具:dmbackup / dmrestore
库已停止时,可用命令行工具直接基于 dm.ini 做全量备份与还原:
# 脱机全量备份
./dmbackup type=full name=all_bak ini_path=/opt/dm.ini
# 全量还原(覆盖)
./dmrestore ini_path=/opt/dm.ini file=/opt/all.bak
# 增量还原(覆盖)
./dmrestore ini_path=/opt/dm.ini file=/opt/add.bak
增量还原与“上一次增量”无关;在还原机器上,bak 文件存放位置要和备份机备份时的文件路径一致。
这句话背后的含义是:增量备份描述的是“相对某个全量/基线备份集的差分”,还原器需要能按原路径语义找到基线与差分的对应关系;路径漂移会让依赖解析失败。
6. 物理备份:备份集(RMAN 风格)—— 理解 RESTORE 与 RECOVER 的分工
“备份集”单独成类,命令形态接近 RMAN:
6.1 全库备份与还原
RMAN> BACKUP DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
FULL BACKUPSET '/all/db_all_bak';
RMAN> RESTORE DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
FROM BACKUPSET '/all/db_all_bak';
RMAN> RECOVER DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
FROM BACKUPSET '/all/db_all_bak';
RMAN> RECOVER DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
UPDATE DB_MAGIC;
RESTORE :把备份集里的物理文件“放回”目标位置(像把积木摆回去)
RECOVER :用备份集内/相关的日志信息,把不一致页修到一致点
UPDATE DB_MAGIC:处理实例身份/库魔数,避免旧控制信息与新恢复文件“认亲失败”
DB_MAGIC 理解成数据库的“身份证号之一”。灾难恢复、克隆库之后,身份对不上就会拒绝启动或拒绝认文件。
6.2 增量备份与还原
-- 增量备份:声明全量目录 + 增量输出目录
RMAN> BACKUP DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
INCREMENT
WITH BACKUPDIR '/bak/all'
BACKUPSET '/bak/add';
-- 增量还原:从增量集还原,同时告诉引擎全量备份目录在哪
RMAN> RESTORE DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
FROM BACKUPSET '/add/add_bak'
WITH BACKUPDIR '/all/all_bak';
RMAN> RECOVER DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
FROM BACKUPSET '/add/add_bak';
RMAN> RECOVER DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
UPDATE DB_MAGIC;
增量不是“再做一次小一点的全量”,而是:
全量备份 = 某时刻几乎完整的页映像基线
增量备份 = 相对基线发生变化的页集合(差分)
还原路径 = 先拿齐基线,再叠差分,再做 recover
6.3 全库还原 + 归档指定时间点(PITR)
这是理解“备份 + 归档”的最佳场景:
RMAN> RESTORE DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
FROM BACKUPSET '/all/db_all_bak';
RMAN> RECOVER DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
WITH ARCHIVEDIR '/opt/dmdbms/data/DAMENG/arch'
UNTIL TIME '2020-07-23 10:48:40';
RMAN> RECOVER DATABASE '/opt/dmdbms/data/DAMENG/dm.ini'
UPDATE DB_MAGIC;
翻译成自然语言:
- 先回到全量备份那一刻的物理底座;
- 再重放归档,把库“快进”到
2020-07-23 10:48:40; - 最后修正库身份信息,准备重新 OPEN。
7. 用 JOB 做“全量 + 增量 + 过期清理”
手册给了一套非常实用的 BAK2 调度思路(单机示例路径):
/opt/dmdbms/data/DAMENG/bak/all ← 全量
/opt/dmdbms/data/DAMENG/bak/add ← 增量
一次性全量 JOB 骨架:
CALL SP_INIT_JOB_SYS(1);
CALL SP_CREATE_JOB('bakall_one',1,0,'',0,0,'',0,'执行一次全量备份');
CALL SP_JOB_CONFIG_START('bakall_one');
CALL SP_ADD_JOB_STEP(
'bakall_one', 'bakall_one_work', 6,
'01000900/opt/dmdbms/data/DAMENG/bak/all',
1, 2, 0, 0, NULL, 0
);
CALL SP_ADD_JOB_SCHEDULE(
'bakall_one', 'bakall_one_time', 1, 0, 0, 0, 0,
NULL, NULL, '2020-05-12 17:38:00', NULL, ''
);
CALL SP_JOB_CONFIG_COMMIT('bakall_one');
增量 + 清理(节选,保留手册关键步骤类型):
CALL SP_CREATE_JOB(
'coun_bakadd_deladd',1,0,'',0,0,'',0,
'每天00点生成统计信息、增量备份、删除32天前的增量(调度周六除外)'
);
CALL SP_JOB_CONFIG_START('coun_bakadd_deladd');
-- 统计信息
CALL SP_ADD_JOB_STEP(
'coun_bakadd_deladd', 'coun', 0,
'CALL SP_DB_STAT_INIT ();',
1, 2, 0, 0, NULL, 0
);
-- 增量:步骤类型 6;串里带全量目录|增量目录
CALL SP_ADD_JOB_STEP(
'coun_bakadd_deladd', 'bakadd', 6,
'11000900/opt/dmdbms/data/DAMENG/bak/all|/opt/dmdbms/data/DAMENG/bak/add',
1, 2, 0, 0, NULL, 0
);
-- 清理过期增量备份集
CALL SP_ADD_JOB_STEP(
'coun_bakadd_deladd', 'deladd', 0,
'SF_BAKSET_BACKUP_DIR_ADD(''DISK'',''/opt/dmdbms/data/DAMENG/bak/add'');
CALL SP_DB_BAKSET_REMOVE_BATCH(''DISK'',SYSDATE-32);',
1, 2, 0, 0, NULL, 0
);
CALL SP_JOB_CONFIG_COMMIT('coun_bakadd_deladd');
也可以直接按目录清理备份集:
SF_BAKSET_BACKUP_DIR_ADD('DISK','/opt/dmdbms/data/DAMENG/bak/all');
CALL SP_DB_BAKSET_REMOVE_BATCH('DISK', SYSDATE-30); -- 保留 30 天
注意:删文件不等于删备份元数据;能走达梦备份集清理接口时,优先走接口,避免“文件没了但库仍以为备份集存在”的脏状态。
8. 读备份文件
-- 全量 / 增量 / B树
SELECT DECODE(SF_BAK_GET_TYPE('/opt/bak/all.bak'),'0','全量','1','增量','2','B树');
-- 联机 / 脱机
SELECT DECODE(SF_BAK_GET_LEVEL('/opt/bak/all.bak'),'0','联机备份','1','脱机备份');
SELECT SF_BAK_GET_TIME('/opt/bak/all.bak'); -- 备份时间
SELECT SF_BAK_GET_EXTENT_SIZE('/opt/bak/all.bak')||'页'; -- 簇大小
SELECT SF_BAK_GET_PAGE_SIZE('/opt/bak/all.bak')/1024||'K'; -- 页大小
SELECT SF_BAK_GET_GLOBAL_VERSION('/opt/bak/all.bak'); -- 库版本
SELECT DECODE(SF_BAK_GET_ARCH_FLAG('/opt/bak/all.bak'),'0','未归档','1','归档');
SELECT DECODE(SF_BAK_GET_ENCRYPT_TYPE('/opt/bak/all.bak'),'0','未加密','1','加密');
SELECT DECODE(SF_BAK_GET_COMPRESSED('/opt/bak/all.bak'),'0','未压缩','1','压缩');
这些字段告诉你:备份是否与当前库的页大小/版本兼容,是否加密压缩,是联机还是脱机产物。
恢复演练前先读元数据,比恢复失败后再排查省几小时。
9. 决策树
只想迁几张表 / 做开发灌数?
└─ 用 dexp/dimp(逻辑)
单表误删、要快速覆盖回去?
└─ BACKUP TABLE / RESTORE TABLE(物理表级)
生产库要防磁盘损坏、要可 PITR?
├─ 开归档
├─ 周期性 FULL(SQL BACKUP / JOB / RMAN BACKUPSET)
├─ 日常 INCREMENT
└─ 定期做一次“停库还原演练”或“备机还原演练”
整库灾难、目标是尽快拉起?
└─ 物理备份集 + RESTORE/RECOVER(通常快于全库 dimp)
逻辑备份解决“对象可搬运”;物理备份解决“实例可重生”;归档解决“时间可回放”。
三者不是互斥,生产上常常是组合拳。
10. 常见问题
-
没开归档就上联机物理备份策略
结果:备份看似成功,恢复时缺少补齐变更的原料,PITR 直接不可用。 -
增量还原时路径不一致
差分备份依赖基线定位;路径漂了,就像差分补丁找不到原安装包。 -
把
dimp当成物理灾难恢复唯一手段
全库逻辑导出/导入可以救急,但耗时长、对象依赖多,且不是页级一致快照路线。 -
只备份、从不演练
备份文件存在 ≠ 可恢复。SF_BAK_GET_*读元数据 + 定期还原演练,才是闭环。 -
Windows 管道连接失败
权限/dmap代理服务未就绪时,还原通道建不起来——这是环境问题,不是备份文件坏了。 -
清理策略只删 OS 文件
优先用备份集清理接口;OS 脚本当辅助,不当时唯一真相源。
11. 知识集
1. 归档是联机备份与 PITR 的地基
2. dexp/dimp = 逻辑对象通道(灵活、偏迁移)
3. BACKUP/dmbackup/RMAN = 物理页映像通道(快、偏容灾)
4. 全量是基线,增量是差分
5. RESTORE 摆文件,RECOVER 修一致,UPDATE DB_MAGIC 对齐身份
6. 增量还原对路径敏感
7. JOB 负责周期化;清理接口负责生命周期
8. 没演练过的备份,只是“看起来安心的文件”
备份还原不是“多敲几条命令”的技能,而是对数据库状态机的理解:
页、日志、LSN、备份集、库身份 五者如何在故障时刻重新拼成一个可 OPEN 的实例。
更多推荐


所有评论(0)