
项目地址: GitHub
版本下载: GitHub Releases
项目简介#
DMDUL 是一个使用 Go 编写的达梦数据库离线恢复与数据抽取工具。
当数据库无法正常 open、控制文件或日志链路异常、常规恢复手段无法继续,但仍能取得 SYSTEM.DBF、可选的 dm.ctl 以及用户表空间 DBF 文件时,DMDUL 可以直接从离线物理文件中:
- 识别数据库页大小、簇大小、字符集、大小写敏感标志等初始化参数;
- 恢复用户、表、字段、索引、约束、视图、序列、过程、函数、包、触发器、同义词和授权;
- 将表数据导出为 SQL、CSV 或达梦原生兼容的纯数据 DMP;
- 尝试恢复
DELETE、DROP、TRUNCATE后尚未被覆盖的物理残留数据; - 处理分区表、行外 LOB、Long Row、大表和超过 4 GiB 的输出场景。
DMDUL 不是 DMRMAN、归档恢复、闪回、dexp 的替代品。它更适合数据库已经无法通过正常路径恢复时,作为最后一道离线救援手段。所有导出结果都应先在隔离测试库验证。
为什么要做 DMDUL#
达梦数据库发生严重故障后,常规处理通常优先依赖备份、归档、控制文件和数据库自身恢复机制。但在以下场景中,DBA 可能只剩下一组 DBF 文件:
- 实例无法正常启动或无法打开;
- 控制文件、ROLL、REDO 或归档链路不完整;
- 误执行
DROP、TRUNCATE后需要验证物理页是否仍有残留; - 需要研究 SYSTEM 表空间、系统字典和数据页的真实组织方式;
- 需要从损坏库中尽可能多地恢复 DDL 和业务数据。
DMDUL 的核心思路不是“猜测 SQL”,而是建立一条从原始物理地址到逻辑对象的证据链:
SYSTEM.DBF / dm.ctl / user tablespace DBF
|
v
Standard Bootstrap
|
v
Dictionary Recovery
|
+---------+---------+---------+
| | | |
v v v v
DDL SQL CSV DMP
|
v
dimp
|
v
Dameng Database对 SYSTEM.DBF 的结构理解#
下图概括了 DMDUL 当前对 SYSTEM.DBF 的结构理解:从文件头和初始化参数区出发,定位 SYSOBJECTS、SYSCOLUMNS、SYSCOLINFOS 等核心字典,再逐步还原用户、表、列和类型信息。

Standard Bootstrap#
DMDUL 的 bootstrap; 不只是全文件关键字扫描,而是优先采用两阶段标准字典下载流程:
第一阶段:定位核心字典入口
- 从
SYSTEM.DBFpage 0 的 anchor 定位SYSOBJECTS; - 定位
SYSINDEXES; - 读取 storage root;
- 解析 root/internal/leaf 页链;
- 校验页地址、页类型和 storage identity。
第二阶段:下载扩展字典
根据第一阶段恢复的对象信息,继续定位并解析:
SYSCOLUMNS;SYSTEXTS;SYSGRANTS;- 分区相关系统字典;
- 视图、过程、函数、包、触发器和授权源码。
当 anchor、root page 或 leaf chain 损坏时,DMDUL 才回退到按页流式扫描,并在 dul.log 中记录 fallback 原因。
数据页与行记录#
下面是基于 DMDUL 研究和实验整理的典型 DM8 8K 数据页示意图。

典型数据页可概括为:
- 低地址区域保存页头和行记录;
- 行记录从低地址向高地址增长;
- slot directory 通常位于高地址区域并向低地址增长;
- slot 中保存行记录偏移;
- 页尾还可能保存校验摘要、标志和其他尾部元数据。
行头语义#
在真实样例中,行记录开头的两个字节应按大端 u16 解释:
低 15 位:物理行长度
0x8000 :DELETE 标志因此:
00 2E 00 ...表示物理行长为 0x002E = 46 字节,第三字节才进入列 metadata。它不能被解释为“0x2E 代表删除行”。
普通 unload 只解析 slot directory 中可寻址的记录;删除 slot、无 slot 物理空洞以及 DROP/TRUNCATE 后的残留页,只由 recover table 恢复模式扫描。
PAGE_CHECK#
DMDUL 当前支持识别 DM8 常见 PAGE_CHECK 模式:
| 模式 | 处理方式 |
|---|---|
0 | 无页校验 |
1 | 页头 0x18 的 CRC32/IEEE |
2 | 页尾 HASH,slot 目录需按摘要长度前移 |
3 | 页头 0x18 的 CRC32C/Castagnoli |
这使 SYSTEM 字典页、分区页和普通数据页在不同 PAGE_CHECK 配置下仍能正确定位 slot directory。
上述结构来自 DMDUL 项目研究、差分实验和真实样例观察,不是达梦官方文件格式规范。不同 DM8 版本、表类型和存储策略可能存在差异。
表数据定位:不再默认扫描整个数据文件#
DMDUL 当前正常表数据导出采用 page plan 直读:
storage_id / root_file / root_page
|
v
root page
|
+-----+-----+
| |
0x14 0x15
leaf/data root/internal
| |
+-----+-----+
|
v
leaf next chain
|
v
ReadAt planned pages执行顺序如下:
- 从磁盘字典取得表或叶子分区的
storage_id、root_file、root_page; - 读取 root page;
- root 为
0x14时按 leaf/data page 处理; - root 为
0x15时解析 BTree root/internal child refs; - 沿 leaf 页 next 链生成 page plan;
- 计划成功后,仅使用
ReadAt读取计划页; - 每个计划页再次校验 group/file/page identity、page kind 和 storage id。
仅在主路径失败时,才依次执行:
同 group 文件按 storage_id 扫描
-> segment range fallback
-> recover table 全文件残留页扫描因此,普通 unload table、unload user 和 unload database 不再默认全面扫描整个数据文件。控制台和 dul.log 会记录:
planned pages: 12
direct pages read: 12
fallback pages scanned: 0
fallback reason: none支持恢复的对象#
DMDUL 当前可以离线恢复或生成以下对象 DDL:
- 用户和角色授权;
- 表、字段、默认值、注释;
- 索引、主键、唯一约束、外键、CHECK 约束;
- RANGE、LIST、HASH 分区表;
- 视图;
- 序列;
- 存储过程、函数、包和包体;
- 触发器;
- 同义词;
- 表、视图和序列等对象授权。
bootstrap; 会将结果持久化到 dmdul_dict/:
dmdul_dict/
├── meta.tsv
├── users.tsv
├── tables.tsv
├── columns.tsv
├── views.tsv
├── sequences.tsv
├── routines.tsv
├── triggers.tsv
├── synonyms.tsv
└── tab_privs.tsv这些 TSV 文件可以人工审查和修订。再次启动后执行:
DMDUL> load dictionary;即可直接使用磁盘字典,不必重复扫描 SYSTEM.DBF。
SQL、CSV 与 DMP 三种数据格式#
DMDUL 支持三种数据导出格式:
DMDUL> set data_format sql;
DMDUL> set data_format csv;
DMDUL> set data_format dmp;其中 SQL 为默认格式。
SQL#
生成可人工审查的 INSERT INTO 语句,适合小规模恢复和复杂类型核查。
DMDUL> unload table HR_TEST.EMP_INFO;CSV#
每张非空表生成一个 CSV 文件,适合数据分析、人工检查和中间迁移。
DMDUL> set data_format csv;
DMDUL> unload user HR_TEST;达梦 DMP#
DMDUL 可以生成可由达梦官方 dimp 装载的纯数据 DMP:
DMDUL> set data_format dmp;
DMDUL> unload table HR_TEST.EMP_INFO;
DMDUL> unload user HR_TEST;
DMDUL> unload database;主要特性包括:
- 表级、用户级和整库级导出;
- 每张表一个 DMP,便于逐表重试和并行导入;
- UTF-8、GB18030、EUC-KR 文件头;
- RANGE、LIST、HASH 分区表;
- 行外 CLOB/BLOB locator 页链流式读取;
STORAGE(USING LONG ROW);- 64 位长度和多 phase 输出;
- 整表或整份 DMP 超过 4 GiB;
- 自动写入 page size、extent size、charset 和
CASE_SENSITIVE。
示例导入:
dimp SYSDBA/password \
FILE=HR_TEST_EMP_INFO_data.dmp \
DATA_ONLY=Y \
FAST_LOAD=Y需要注意:
- JSON/JSONB 表应使用
FAST_LOAD=N; - 当前已验证的 DMP 路径不能无损保存
TIME小数秒,要求无损时应使用 SQL 或 CSV; - DMP 是纯数据文件,对象、用户和授权仍由 DDL SQL 恢复。
数据类型覆盖#
DMDUL 已覆盖常见 DM8 类型的 DDL、SQL、CSV 和 DMP 路径,包括:
- BIT、BYTE、BINARY、RAW、PLS_INTEGER;
- INT、BIGINT、NUMBER、DECIMAL;
- REAL、FLOAT、DOUBLE;
- CHAR、VARCHAR、VARCHAR2、国家字符类型;
- DATE、TIME、DATETIME、TIMESTAMP;
- 带时区时间类型;
- 13 种 INTERVAL;
- ROWID、BFILE;
- JSON、JSONB;
- CLOB、BLOB、TEXT、IMAGE;
- 行内 LOB、行外 LOB 和 Long Row。
快速开始#
准备文件#
建议将文件放在同一工作目录:
D:\temp\oldpro\
├── SYSTEM.DBF
├── dm.ctl
├── MAIN.DBF
├── ROLL.DBF
├── TEMP.DBF
└── TBS_*.DBF启动交互模式#
Windows:
.\dmdul.exeLinux:
./dmdul标准流程#
DMDUL> set system D:\temp\oldpro\SYSTEM.DBF;
DMDUL> set data_dir D:\temp\oldpro;
DMDUL> bootstrap;
DMDUL> show parameter;
DMDUL> list user;
DMDUL> list table HR_TEST;
DMDUL> unload object HR_TEST;
DMDUL> set data_format dmp;
DMDUL> unload user HR_TEST;
DMDUL> exit;执行后目录结构类似:
D:\temp\oldpro\
├── control.dul
├── init.dul
├── dul.log
├── dmdul_dict\
└── output\
├── HR_TEST_ddl.sql
├── HR_TEST_EMP_INFO_data.dmp
└── ...DROP、TRUNCATE 与 DELETE 残留恢复#
表被 TRUNCATE 或 DROP 后,只要原数据页尚未被重新覆盖,就可能仍保留物理内容:
DMDUL> recover table USERS1.T_TEST;如果表已被 DROP,当前 SYSTEM 字典中可能已经不存在表定义,需要:
- 加载 DROP 前保存的
dmdul_dict; - 或人工补齐
tables.tsv和columns.tsv; - 必要时补充
storage_id、root_file、root_page和assist_ids。
普通 unload 与 recover table 的语义不同:
- 普通
unload:slot-only,面向当前可寻址物理记录; recover table:允许读取删除 slot、无 slot 空洞和残留页。
但 slot-only 仍不等同于 committed-only。未提交 INSERT/DELETE 的最终可见性,仍需要后续离线事务状态和完整 Undo PRE IMAGE 链才能准确判断。
常用命令#
bootstrap;
load parameter;
load dictionary;
show parameter;
list user;
list table <owner>;
unload object <owner|all>;
unload table <owner.table_name>;
unload user <owner>;
unload database;
recover table <owner.table_name>;
set data_format sql;
set data_format csv;
set data_format dmp;
set output_dir <directory>;
exit;DMDUL 已移除原来的功能性命令行子命令。现在只保留:
dmdul
dmdul help
dmdul version所有恢复和卸载操作统一在交互式 Shell 中完成。
当前边界#
DMDUL 仍处于持续研究和验证阶段,当前边界包括:
- 工具只读 DBF,不会修改原始数据文件;
- 导出的 DDL、SQL、CSV 和 DMP 必须先在隔离测试库验证;
- DROP/TRUNCATE 恢复依赖原数据页是否已经被覆盖;
- DMP 当前是纯数据文件,不包含完整
dexp元数据; - 行外 LOB、Long Row、损坏页和断链场景仍需要更多样例;
- 迁移行、链式行尚未进行未经验证的跨页拼接;
- 普通 slot-only 解析不等于事务一致性恢复;
- 不保证恢复结果与故障前数据库在事务层面完全一致。
下载与参与#
Windows 和 Linux x64 版本可从 GitHub Releases 下载:
欢迎提交 Issue、失败样例、测试数据和 Pull Request。对于离线恢复项目而言,真实失败案例和可重复实验样例比单纯增加代码更有价值。
本文中的 SYSTEM.DBF 和数据页示意图均基于 DMDUL 项目的研究与实验观察,仅用于解释解析思路,不代表达梦官方文件格式规范。