注册
从“拷文件”到“一致性恢复”:达梦数据库备份与还原入门
技术分享/ 文章详情 /

从“拷文件”到“一致性恢复”:达梦数据库备份与还原入门

🌌 2026/08/07 146 0 0

1. 备份到底在保护什么?

最初最容易把备份想成:

“把数据文件拷一份,坏了再拷回去。”

对文件系统级冷拷而言,这句话有时够用;对数据库却不够。数据库真正需要保护的是:

  1. 数据页(Data Page):表数据、索引最终落在磁盘上的页;
  2. 事务日志(Redo / Archive):把“改了什么”按时间顺序记下来;
  3. 元数据与实例身份:控制文件、dm.ini、库的 MAGIC 等,决定实例能不能识别这套数据文件。

一次“可用的恢复”,本质是把库拉回到某个一致的状态点——要么是备份完成瞬间的一致性,要么是备份点之后、再用归档日志“滚”到的某个时间点。

可以先记这张关系图:

业务写入
   │
   ▼
共享缓冲 / 数据页修改 ──► 刷盘到 .dbf(慢路径、异步)
   │
   ▼
Redo 日志(在线日志)──► 归档日志(开启 ARCHIVELOG 后)
   │
   ▼
备份集 / .bak / .dmp  ←── 你真正要保管的“恢复原料”
  • 逻辑备份dexp/dimp):导出的是对象与行数据的“可移植副本”,不依赖原库页布局。
  • 物理备份BACKUP/dmbackup/RMAN BACKUPSET):拷的是页级/库级物理映像,恢复快,但对路径、页大小、版本更敏感。
  • 归档:联机备份和“指定时间点恢复(PITR)”的地基。没有归档,很多联机能力会缺一条腿。

2. 逻辑/物理、联机/脱机、全量/增量

维度 选项 理解
形态 逻辑(dmp) / 物理(bak / 备份集) 逻辑像“导出 Excel”;物理像“整盘快照”
时机 联机(不停服务) / 脱机(停服务) 联机靠归档补齐“备份过程中还在变的页”;脱机则库本身静止
粒度 表 / 模式 / 用户 / 全库;全量 / 增量 粒度越小越灵活;全量是基线,增量是差分

关键词:

  • 覆盖还原:物理 restore table / dmrestore / RMAN RESTORE 往往会覆盖目标对象或整个库文件。
  • 非覆盖还原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 风格)—— 理解 RESTORERECOVER 的分工

“备份集”单独成类,命令形态接近 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;

翻译成自然语言:

  1. 先回到全量备份那一刻的物理底座;
  2. 再重放归档,把库“快进”到 2020-07-23 10:48:40
  3. 最后修正库身份信息,准备重新 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. 常见问题

  1. 没开归档就上联机物理备份策略
    结果:备份看似成功,恢复时缺少补齐变更的原料,PITR 直接不可用。

  2. 增量还原时路径不一致
    差分备份依赖基线定位;路径漂了,就像差分补丁找不到原安装包。

  3. dimp 当成物理灾难恢复唯一手段
    全库逻辑导出/导入可以救急,但耗时长、对象依赖多,且不是页级一致快照路线。

  4. 只备份、从不演练
    备份文件存在 ≠ 可恢复。SF_BAK_GET_* 读元数据 + 定期还原演练,才是闭环。

  5. Windows 管道连接失败
    权限/dmap 代理服务未就绪时,还原通道建不起来——这是环境问题,不是备份文件坏了。

  6. 清理策略只删 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 的实例。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服