惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
博客园 - Franky
L
LangChain Blog
GbyAI
GbyAI
A
About on SuperTechFans
MongoDB | Blog
MongoDB | Blog
F
Fortinet All Blogs
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
N
Netflix TechBlog - Medium
D
DataBreaches.Net
Martin Fowler
Martin Fowler
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
爱范儿
爱范儿
罗磊的独立博客
H
Help Net Security
云风的 BLOG
云风的 BLOG
C
Check Point Blog

博客园 - 风哥数据库教程

数据库教程FGMT20‑Oracle容灾体系架构与数据库升级迁移方案 数据库教程FGMT19‑Oracle多租户容器架构与新特性总结 数据库教程FGMT18‑Oracle‑EMCC智能化集中运维管理系统 数据库教程FGMT17‑Oracle性能优化之故障诊断与性能优化 数据库教程FGMT16‑Oracle性能优化之操作系统诊断与分析 数据库教程FGMT15‑Oracle性能优化之物化视图与任务管理 数据库教程FGMT14‑Oracle性能优化之资源限制与资源管理 数据库教程FGMT13‑Oracle性能优化之数据仓库与分区表 数据库教程FGMT12‑Oracle性能诊断与综合分析 数据库教程FGMT11‑Oracle性能优化之性能收集与报告分析 数据库教程FGMT10‑Oracle性能优化之统计信息管理与维护 数据库教程FGMT09‑Oracle性能优化之执行计划与基线管理 数据库教程FGMT08‑Oracle性能优化之基准测试与案例分析 数据库教程FGMT06‑Oracle数据库日常管理维护操作 数据库教程FGMT07‑Oracle数据库备份恢复与数据迁移 数据库教程FGMT05‑Oracle数据库SQL语言开发与应用实战 数据库教程FGMT03‑生产环境Linux+Oracle19c+ASM安装配置与项目实战 数据库教程FGMT01‑Oracle数据库基础知识与版本特性 数据库教程FGMT00‑教程学习大纲与学习指南(第一部) MySQL 8/9集群InnoDB Cluster自动化安装过程-Fgedu MySQL8/9 MGR组复制集群安装自动化全过程-Fgedu MySQL8/9主从复制集群安装自动化全过程-Fgedu MySQL8.x/9.x数据库安装自动化全过程-Fgedu 异构数据库迁移全过程-FGO2ODB工具 从国外数据库迁移到国产数据库全过程-FGO2CDB工具 Oracle迁移到PostgreSQL数据库-FGOracle2PG工具 MySQL迁移到PostgreSQL数据库-FGMySQL2PG工具 Oracle 26ai数据库一键自动安装 for Fgedu Oracle 19c数据库一键自动安装 for Fgedu 数据库数据文件误删恢复工具FGFDU(FGEDU File DUL)
华为高斯数据库恢复工具FGOGDU(FGEDU openGauss DUL)
风哥数据库教程 · 2026-08-30 · via 博客园 - 风哥数据库教程

华为高斯数据库恢复工具FGOGDU(FGEDU openGauss DUL)

FGOGDU(全称 **FGEDU openGauss DUL**)是一款专门面向 openGauss 数据库的离线数据抽取与恢复工具,将“绕过数据库实例、直接从底层数据文件中读取并还原数据”这一经典思路移植到 openGauss 生态,填补了 openGauss 在“数据库无法启动”这一极端故障场景下数据抢救工具的空白。

---

## 目录

1. [程序介绍](#一程序介绍)

2. [程序功能与特性](#二程序功能与特性)

3. [程序使用](#三程序使用)

4. [程序各种案例场景与操作过程](#四程序各种案例场景与操作过程)

5. [常用问题与排查](#五常用问题与排查)

6. [附录](#六附录)

---

## 一、程序介绍

### 1.1 工具概述

FGOGDU(全称 **FGEDU openGauss DUL**)是一款专门面向 openGauss 数据库的离线数据抽取与恢复工具,,将“绕过数据库实例、直接从底层数据文件中读取并还原数据”这一经典思路移植到 openGauss 生态,填补了 openGauss 在“数据库无法启动”这一极端故障场景下数据抢救工具的空白。

在传统的运维与故障恢复流程中,当 openGauss 数据库实例因为控制文件损坏、参数文件丢失、系统表空间坏块、redo 日志断裂、升级失败或人为误操作等原因而无法正常启动时,运维人员通常只能依赖物理备份(全量备份 + 归档日志)或逻辑备份(gs_dump 导出文件)进行恢复。然而现实情况往往是:备份策略不完备、备份介质同样损坏、备份时间点与故障点之间存在较大数据落差,甚至根本没有可用备份。此时数据库实例无法启动,意味着所有 SQL 接口(gsql、JDBC、ODBC)全部失效,业务数据被“锁”在磁盘上的数据文件中而无法访问。

FGOGDU 正是为解决这一痛点而生。它不依赖 openGauss 实例运行,也不依赖任何数据库客户端库,而是直接以文件方式读取 `base/`、`global/` 目录下的数据文件,按照 openGauss/PostgreSQL 的 Astore heap 存储格式逐页、逐元组地解析,将磁盘上残存的数据还原为可读的 SQL 文本或自描述的 DMP 二进制文件,供运维人员导入到新的、健康的数据库实例中,从而完成数据的最终恢复。

工具编译后生成单个约 2MB 的完全静态链接可执行文件 `fgogdu`,不依赖任何动态共享库(.so),可直接通过 scp/U 盘等方式拷贝到任意 Linux 服务器上运行,真正做到“即拷即用、零安装、零依赖”。这一特性在故障应急场景下尤为重要:恢复现场的服务器往往环境残缺、无法联网安装依赖,而 FGOGDU 单文件部署的方式极大降低了恢复门槛。

### 1.2 设计理念

FGOGDU 在设计上遵循以下核心理念:

- **数据安全优先**:工具只读不写,绝不在源数据文件上做任何修改,所有恢复结果均输出到独立的输出目录,确保故障现场不被二次破坏,便于多次尝试不同的恢复策略。

- **尽最大可能恢复**:在坏块、系统目录损坏、TOAST 文件缺失等各种异常场景下,工具不会因单点故障而中断,而是自动降级到兜底策略——跳过坏块、扫描孤立文件、做无表结构的原始元组抽取,尽最大可能抢救磁盘上残存的数据。

- **简单清晰的命令**:命令体系采用“动词 + 宾语”的自然语义结构(如 `recover`、`recover-deleted`、`recover-directory`、`orphan-scan`),主命令使用完整英文单词而非晦涩缩写,降低运维人员的记忆与使用成本。

- **双格式导出**:同时支持 SQL 文本格式与 DMP 二进制格式输出。SQL 格式便于人工阅读、审计与跨版本导入;DMP 格式保留原始二进制数据,适合程序化高速导入。

- **完全静态、零依赖**:编译期完成全部静态链接,运行期无任何外部库依赖,保证在任意老旧或国产化 Linux 发行版上均可稳定运行。

### 1.3 作者信息

作者:风哥

官方网站: http://www.fgedu.net.cn ,  http://www.itpux.com

数据库教程:  https://edu.51cto.com/lecturer/8020378.html

### 1.4 适用人群

FGOGDU 主要面向以下人员:

- **数据库运维 DBA**:负责 openGauss 日常运维与故障应急处置,是本工具的核心使用者。

- **数据恢复工程师**:在客户现场执行紧急数据抢救任务,需要一款便携、可靠、零依赖的恢复工具。

- **系统管理员**:在数据库实例无法启动时,需要从数据目录中提取关键业务数据。

- **数据库研发与测试人员**:用于验证数据存储格式、构建恢复测试用例、研究 openGauss 底层存储机制。

### 1.5 名词解释

| 名词 | 说明 |

|------|------|

| DUL | Data UnLoad,数据卸载工具,源自 Oracle 领域的离线数据抽取工具 |

| Astore | openGauss 的默认行存储引擎,其堆表页格式与 PostgreSQL 兼容 |

| Ustore | openGauss 的 inplace update(原地更新)存储引擎,本工具暂不支持 |

| TOAST | The Oversized-Attribute Storage Technique,超长字段外存机制 |

| LOB | Large Object,大字段,泛指 text/varchar/bytea 等超长变长字段 |

| 数据目录(datadir) | openGauss 的数据目录,包含 base/、global/、pg_control 等 |

| 系统目录 | pg_database、pg_class、pg_attribute 等存储元数据的系统表 |

| 孤立文件 | base/ 目录下未被 pg_class 引用的数据文件,通常是被 DROP/TRUNCATE 的表 |

---

## 二、程序功能与特性

### 2.1 核心功能概览

FGOGDU 围绕“离线数据抽取与恢复”这一核心目标,提供了一套完整的命令体系,覆盖从只读查看到精细恢复再到一键全量恢复的完整链路:

| 功能类别 | 代表命令 | 说明 |

|----------|----------|------|

| 信息查看 | `version` / `help` | 查看工具版本与帮助 |

| 目录探查 | `databases` / `schemas` / `tables` | 列出数据目录中的数据库、模式、表 |

| 诊断分析 | `blocksize` / `page` | 检测块大小、查看数据页结构 |

| 单表恢复 | `recover` / `recover-deleted` | 恢复单个表的活跃数据或含已删除数据 |

| 批量恢复 | `recover-all` / `unload` | 按数据库或按用户名导出所有表 |

| 最大恢复 | `recover-directory` | 一键恢复数据目录下的全部数据 |

| 文件级恢复 | `recover-file` | 用手动模式文件恢复单个原始数据文件 |

| 孤立扫描 | `orphan-scan` | 查找被 DROP/TRUNCATE 的孤立数据文件 |

### 2.2 功能特性详解

#### 2.2.1 完全静态链接,单文件部署

FGOGDU 在编译阶段通过 `-static -static-libgcc -static-libstdc++` 选项完成全部静态链接,生成的 `fgogdu` 可执行文件约 2MB,不依赖任何动态共享库(.so)。通过 `ldd ./fgogdu` 验证应输出“not a dynamic executable”。这意味着:

- 无需安装 openGauss 客户端库(libpq 等)

- 无需安装任何第三方运行时库

- 可直接拷贝到任意 Linux 服务器运行,适合故障现场的“裸环境”部署

- 不受目标服务器 glibc 版本差异影响(在编译机 glibc 版本范围内)

#### 2.2.2 跨平台与国产化支持

工具在 RHEL/OEL/麒麟/欧拉等主流 Linux 发行版上完成编译与验证,覆盖国产化操作系统场景:

- 支持 RHEL 6/7/8/9/10 全系列

- 支持 Oracle Linux(OEL)各版本

- 支持麒麟操作系统(Kylin)

- 支持欧拉操作系统(openEuler)

- 支持 CentOS 7/8 及其衍生版

由于采用静态链接,同一份二进制可在上述所有平台间直接拷贝使用,无需针对不同发行版重新编译。

#### 2.2.3 自动识别数据块大小

openGauss 的数据块大小(blocksize)在初始化时确定,常见取值为 8192(8KB),但也可能配置为 16384(16KB)、32768(32KB)、65536(64KB)。FGOGDU 在读取每个数据文件时会自动检测块大小,无需用户手动指定,检测策略为:

1. 读取页头 `pd_pagesize_version` 字段,从高 15 位提取块大小

2. 若失败,依次尝试常见块大小:8192、16384、32768、65536、4096、2048、1024

3. 对每个候选块大小,验证页头字段(pd_lower、pd_upper、pd_special)的合理性

4. 选定首个通过验证的块大小

对于特殊场景,用户也可通过 `-b/--blocksize` 参数强制指定块大小。

#### 2.2.4 LOB/TOAST 大字段恢复

当 text、varchar、bytea 等变长字段数据超过约 2KB 时,openGauss 会自动将其迁移到 TOAST 表中分块存储。FGOGDU 默认启用 LOB 恢复,无需额外参数,自动完成以下工作:

1. 从 `pg_class` 读取表的 `reltoastrelid`,定位关联的 TOAST 表

2. 读取 TOAST 表的数据文件,按 `chunk_id` 和 `chunk_seq` 顺序重组分块数据

3. 检测数据是否被 pglz 压缩,若压缩则调用内置 pglz 解压器还原原始数据

4. 兼容新旧两种 varatt_external 指针格式(12 字节旧格式 / 16 字节 PG14+ 新格式)

5. 将还原的 LOB 数据导出到 SQL/DMP 文件

单个 LOB 数据最大支持 256MB,防止内存溢出。当 TOAST 表文件缺失或损坏时,对应字段标记为 `<TOASTED>` 而非中断恢复。

#### 2.2.5 多种恢复模式

FGOGDU 提供四种层次的恢复模式,适应不同的故障严重度与数据抢救需求:

- **活跃数据恢复(recover)**:仅恢复表中当前有效的数据行,是最常规的恢复模式。

- **已删除数据恢复(recover-deleted)**:同时恢复活跃数据与已被 DELETE 删除但尚未被新数据覆盖的数据行,用于误删数据的抢救。已删除行在输出文件中标记 `[was-deleted]`。

- **DROP/TRUNCATE 恢复(orphan-scan + recover-file)**:表被 DROP 或 TRUNCATE 后,系统目录中已无该表信息,但底层数据文件可能仍残留在磁盘上。通过孤立文件扫描定位这些文件,再用手动模式文件恢复。

- **全库最大恢复(recover-directory)**:一键恢复数据目录下的全部数据,包含所有数据库的所有表、已删除数据、global/ 共享系统表、孤立文件,并在系统目录损坏时自动兜底。这是应急场景下的首选命令。

#### 2.2.6 系统目录自动解析

FGOGDU 通过读取 openGauss 系统目录自动还原表结构,无需用户手动提供模式定义:

- 从 `global/1262`(pg_database)读取数据库列表与 OID

- 从各数据库的 `pg_class`(OID 1259)读取表信息(表名、OID、filenode、TOAST 关联)

- 从 `pg_attribute`(OID 1249)读取列定义(列名、类型 OID、是否可空、顺序)

- 从 `pg_namespace` 读取模式(schema)名

基于系统目录解析,工具能够自动生成 `CREATE TABLE` 语句并按列顺序正确解码元组数据。

#### 2.2.7 共享目录支持

openGauss 的 `global/` 目录下存放跨数据库共享的系统表(如 pg_database、pg_shadow、pg_tablespace 等)。FGOGDU 在 `recover-directory` 最大恢复模式下会自动恢复 global/ 目录下的共享系统表,确保恢复结果完整。

#### 2.2.8 系统目录损坏兜底恢复

当系统目录因坏块而无法读取时,FGOGDU 会自动降级到兜底策略,尽最大可能抢救数据:

- **pg_database 不可读**:自动扫描 `base/` 目录下的数字子目录,将每个数字子目录名作为数据库 OID 继续恢复。

- **pg_class 不可读**:对该数据库下所有数据文件做无表结构的原始元组抽取,以十六进制原始数据形式导出到 `_orphan/` 目录,保留磁盘上残存的所有信息。

- **坏块自动跳过**:遇到损坏的数据页时自动跳过,继续恢复后续正常页,避免单点故障导致整表恢复失败。

#### 2.2.9 丰富的数据类型支持

FGOGDU 支持 openGauss 常用的全部基础数据类型,包括:

| 类型 | OID | 说明 |

|------|-----|------|

| boolean | 16 | 布尔值 |

| bytea | 17 | 二进制数据 |

| char | 18 | 单字节字符 |

| name | 19 | 64 字节固定长度名称 |

| int8 / bigint | 20 | 8 字节整数 |

| int2 / smallint | 21 | 2 字节整数 |

| int4 / integer | 23 | 4 字节整数 |

| text | 25 | 变长文本 |

| oid | 26 | 对象标识符 |

| float4 / real | 700 | 单精度浮点 |

| float8 / double | 701 | 双精度浮点 |

| bpchar | 1042 | 定长字符 |

| varchar | 1043 | 变长字符 |

| nvarchar2 | 4191 | openGauss nvarchar2 |

| date | 1082 | 日期 |

| time | 1083 | 时间 |

| timestamp | 1114 | 时间戳 |

| timestamptz | 1184 | 带时区时间戳 |

| numeric | 1700 | 精确数值 |

| uuid | 2950 | UUID |

| json | 114 | JSON |

| jsonb | 3802 | 二进制 JSON |

| xml | 142 | XML |

特别地,numeric 类型采用按十进制位渲染的算法,正确处理 openGauss/PostgreSQL 12+ 的 NumericShort 与 NumericLong 两种磁盘格式,以及 NaN / ±Infinity 特殊值,兼容老版本(pre-PG12)的 8 字节头格式作为回退。

#### 2.2.10 双格式导出(SQL + DMP)

- **SQL 格式(.sql)**:每个表生成一个 SQL 文本文件,包含 `CREATE TABLE` 语句(自动还原表结构)和 `INSERT INTO` 语句(每行一条),便于人工阅读、审计与跨版本导入。

- **DMP 格式(.dmp)**:自描述的二进制格式,文件头标识 `FGOGDUMP`,包含版本号、标志位、表名、列定义、每行数据的原始二进制值以及恢复元数据(块号、偏移、删除状态),适合程序化高速导入。

- 默认同时导出两种格式(`-f both`),也可通过 `-f sql` 或 `-f dmp` 仅导出一种格式以减少 I/O。

#### 2.2.11 实时进度显示

恢复过程中工具会实时输出进度信息,包括:

- 当前正在扫描/导出的数据库名与 OID

- 当前正在导出的表名、模式名

- 每个表导出的行数

- 文件扫描进度与跳过的坏块提示

- 兜底恢复触发时的告警信息

便于运维人员实时掌握恢复进展与故障范围。

### 2.3 支持环境

#### 2.3.1 编译环境要求

| 项目 | 要求 |

|------|------|

| 操作系统 | Linux(x86_64) |

| 编译器 | GCC 4.8+(需支持 C++17 标准) |

| 静态链接库 | glibc-static、libstdc++-static |

| 构建工具 | GNU Make |

| 可选依赖 | 无(不依赖 libpq 或任何 openGauss 客户端库) |

#### 2.3.2 运行环境要求

| 项目 | 要求 |

|------|------|

| 操作系统 | RHEL 6/7/8/9/10、OEL、CentOS 7/8、麒麟(Kylin)、欧拉(openEuler)等 Linux x86_64 |

| 运行时依赖 | 无(完全静态链接,零依赖) |

| 目标数据库 | openGauss 3.x / 5.x(Astore heap 存储格式) |

| 存储引擎 | 仅支持 Astore(openGauss 默认行存格式);不支持 Ustore |

| 权限要求 | 对 openGauss 数据目录有读权限;对输出目录有写权限 |

| 磁盘空间 | 输出目录需预留约源数据体积 1~2 倍的空间(同时导出 SQL+DMP 时) |

#### 2.3.3 已验证环境

- RHEL 7.9 / GCC 9 / openGauss 3.0+

- RHEL 8.6 / GCC 11 / openGauss 5.0+

- Oracle Linux 9 / GCC 12 / openGauss 5.0+

- 麒麟 V10 / GCC 10 / openGauss 5.0+

- 欧拉 22.03 / GCC 10 / openGauss 5.0+

### 2.4 技术架构

FGOGDU 采用模块化 C++ 设计,源代码组织清晰,各模块职责单一:

| 模块 | 源文件 | 职责 |

|------|--------|------|

| 公共定义 | common.h | 页结构、常量、工具函数 |

| 类型系统 | types.h / types.cpp | OID 枚举、列定义、值结构、varlena/numeric/日期/pglz 解码、TOAST 解析 |

| 页面解析 | page.h / page.cpp | 块大小检测、页头验证、元组提取 |

| 关系模型 | relation.h / relation.cpp | Schema、RecoveredRow、元组解码、关系文件扫描 |

| 系统目录 | catalog.h / catalog.cpp | pg_database、pg_class、pg_attribute 解析 |

| 恢复引擎 | recovery.h / recovery.cpp | 单表、全库、孤立文件、TOAST/LOB 恢复 |

| 导出器 | exporter.h / exporter.cpp | SQL/DMP 导出实现 |

| 命令分发 | commands.h / commands.cpp | 命令行解析与执行 |

| 程序入口 | main.cpp | argv 转发与异常处理 |

恢复数据流:数据文件 → 页面解析 → 元组提取 → 类型解码(含 TOAST 重组与 pglz 解压)→ 导出器(SQL/DMP)→ 输出文件。

### 2.5 恢复原理

1. **系统目录解析**:从 `global/1262`(pg_database)读取数据库列表,从各数据库的 `pg_class`(OID 1259)和 `pg_attribute`(OID 1249)读取表结构与列定义。

2. **数据页解析**:读取 Astore heap 格式的数据页,解析页头、行指针(line pointer)与元组头。

3. **元组解码**:根据列定义与数据类型,逐列解码元组数据,正确处理定长与变长(varlena)字段。

4. **已删除数据恢复**:通过 `t_xmax` 与 `t_infomask` 标志识别已删除但尚未被覆盖的元组。

5. **孤立文件恢复**:扫描 `base/<dboid>/` 目录中未被 `pg_class` 引用的数据文件,定位被 DROP/TRUNCATE 的表。

6. **系统目录损坏兜底**:pg_database 不可读时扫描 `base/` 数字子目录;pg_class 不可读时做无表结构原始元组抽取。

7. **LOB/TOAST 恢复**:解析 varatt_external 指针(12/16 字节),读取 TOAST 表文件按 chunk 顺序重组,通过内置 pglz 解压器还原压缩数据。

### 2.6 已知限制

- 仅支持 Astore 存储引擎(openGauss 默认行存格式);不支持 Ustore 原地更新存储引擎。

- 不支持 LZ4 压缩的 TOAST 数据(openGauss 默认使用 pglz,已支持)。

- 内联压缩的 varlena 数据(非 TOAST)标记为 `<COMPRESSED>`,暂不支持解压。

- 已被新数据物理覆盖的删除行无法恢复。

- TOAST 表文件缺失时,对应 LOB 字段标记为 `<TOASTED>`,不影响其他字段与其他行的恢复。

---

## 三、程序使用

### 3.1 编译与安装

#### 3.1.1 环境准备

确保编译机已安装 GCC(支持 C++17)及静态链接库:

```bash

# RHEL/OEL/CentOS

dnf install gcc gcc-c++ glibc-static libstdc++-static make

# Oracle Linux 需启用 CodeReady Builder 仓库

dnf config-manager --set-enabled ol9_codeready_builder

dnf install glibc-static libstdc++-static

```

#### 3.1.2 一键编译

```bash

cd /path/to/FGOGDU

./build.sh

```

`build.sh` 会自动执行:清理旧目标 → 并行编译 → 验证静态链接 → 运行版本自检。

#### 3.1.3 手动编译

```bash

make clean && make -j$(nproc)

```

#### 3.1.4 验证静态链接

```bash

ldd ./fgogdu

# 期望输出: not a dynamic executable(或:不是动态可执行文件)

```

#### 3.1.5 部署

编译完成后生成 `fgogdu` 可执行文件(约 2MB),直接拷贝到目标服务器即可使用:

```bash

scp fgogdu user@target:/tmp/

ssh user@target "chmod +x /tmp/fgogdu && /tmp/fgogdu version"

```

### 3.2 命令总览

```

USAGE:  fgogdu <command> [options]

COMMANDS (simple & clear):

  version                       显示版本信息

  help                          显示帮助

  databases <datadir>           列出数据目录中的所有数据库

  schemas   <datadir> <db>      列出数据库中的模式

  tables    <datadir> <db> [schema]   列出表(可按模式过滤)

  blocksize <file>              自动检测数据文件的块大小

  page      <file> <blkno> [blocksize]  查看数据页信息(诊断用)

RECOVERY (export to SQL/DMP, one file per table):

  recover          <datadir> <db> <schema> <table>   恢复单个表的活跃数据

  recover-deleted  <datadir> <db> <schema> <table>   恢复活跃+已删除数据

  recover-all      <datadir> [db] [--max]            全库导出

  unload           <datadir> <db> [-o outdir] [-f fmt] [--max]  按用户名 unload

  recover-directory <datadir>                        最大恢复:按目录导出所有数据

  recover-file     <file> -s <schemafile> [name]     用模式文件恢复原始数据文件

  orphan-scan      <datadir> <db>                    查找孤立文件

```

### 3.3 查看命令详解

#### 3.3.1 version - 显示版本信息

```bash

./fgogdu version

```

输出示例:

```

FGOGDU 1.0  (FGEDU openGauss DUL)

openGauss data unload & recovery tool (Astore heap format)

Static build, no runtime dependencies.

```

#### 3.3.2 help - 显示帮助

```bash

./fgogdu help

```

显示所有命令与选项的简要说明。

#### 3.3.3 databases - 列出数据库

```bash

./fgogdu databases /opengauss/data

```

输出示例:

```

OID        NAME

14448      postgres

1          template1

14447      template0

```

`<db>` 参数既可使用数据库名称,也可直接使用 OID 数字。

#### 3.3.4 schemas - 列出模式

```bash

./fgogdu schemas /opengauss/data postgres

```

输出示例:

```

NSPOID     NAME

11         pg_catalog

2200       public

16384      my_schema

```

#### 3.3.5 tables - 列出表

```bash

# 列出所有表

./fgogdu tables /opengauss/data postgres

# 列出指定模式下的表

./fgogdu tables /opengauss/data postgres public

```

输出示例:

```

OID        FILENODE   SCHEMA               TABLE              COLS

16384      16384      public               users              5

16385      16385      public               orders             8

16390      16390      my_schema            products           4

```

#### 3.3.6 blocksize - 检测块大小

```bash

./fgogdu blocksize /opengauss/data/base/14448/16384

# 输出: 8192

```

通常无需手动指定,工具会自动检测。此命令用于诊断目的。

#### 3.3.7 page - 查看数据页

```bash

./fgogdu page /opengauss/data/base/14448/16384 0

./fgogdu page /opengauss/data/base/14448/16384 5 8192

```

输出示例:

```

block 0  size=8192 lower=48 upper=7920 special=8192 version=4

lineptrs=6 normal=6 redirect=0 dead=0 unused=0 tuples=6

  off=1  len=64   xmin=1000   xmax=0      natts=5  live

  off=2  len=64   xmin=1001   xmax=2000   natts=5  del

```

用于诊断数据页结构与元组状态(live/del/DEAD)。

### 3.4 恢复命令详解

#### 3.4.1 recover - 恢复单个表

```bash

./fgogdu recover <datadir> <db> <schema> <table> [-o outdir] [-f fmt] [--max]

```

参数说明:

- `<datadir>`:openGauss 数据目录(包含 base/ 和 global/)

- `<db>`:数据库名或 OID

- `<schema>`:模式名(如 public)

- `<table>`:表名

示例:

```bash

# 恢复 public.orders 表

./fgogdu recover /opengauss/data postgres public orders -o /backup

# 仅导出 SQL 格式

./fgogdu recover /opengauss/data postgres public orders -o /backup -f sql

# 最大恢复模式(包含已删除数据,遇到错误继续)

./fgogdu recover /opengauss/data postgres public orders -o /backup --max

```

输出:在输出目录中生成 `schema.table.sql` 和/或 `schema.table.dmp` 文件。

#### 3.4.2 recover-deleted - 恢复已删除数据

```bash

./fgogdu recover-deleted <datadir> <db> <schema> <table> [-o outdir] [-f fmt]

```

恢复活跃数据 + 已删除数据(UNDELETE)。已删除的行在 SQL 文件中标记为:

```sql

-- recovered row blk=0 off=2 [was-deleted]

INSERT INTO public.orders (...) VALUES (...);

```

#### 3.4.3 recover-all - 全库导出

```bash

# 导出单个数据库

./fgogdu recover-all <datadir> <db> [-o outdir] [--max]

# 导出所有数据库

./fgogdu recover-all <datadir> [-o outdir] [--max]

```

- `--max` 模式包含已删除数据、孤立文件扫描,遇到错误继续。

- 每个数据库的数据导出到 `<outdir>/<dbname>_<dboid>/` 子目录。

#### 3.4.4 unload - 按用户名 unload

```bash

./fgogdu unload <datadir> <db> [-o outdir] [-f fmt] [--max]

```

| 参数 | 说明 |

|------|------|

| `<datadir>` | openGauss 数据目录 |

| `<db>` | 数据库名(在 openGauss 中用户名通常对应数据库名) |

| `-o` | 输出目录(默认 ./recover_out) |

| `-f` | 输出格式:sql / dmp / both(默认 both) |

| `--max` | 最大恢复:包含已删除数据 |

示例:

```bash

# 按用户名 unload,导出 fgedudb 下所有表(SQL + DMP)

./fgogdu unload /opengauss/data fgedudb -o /backup -f both

# 最大恢复模式(包含已删除数据)

./fgogdu unload /opengauss/data fgedudb -o /backup --max

```

输出目录结构:

```

/backup/

└── fgedudb/                          # 以用户名(数据库名)命名的子目录

    ├── fgeduschema.fgedu01.sql       # 每个表一个 SQL 文件

    ├── fgeduschema.fgedu01.dmp       # 每个表一个 DMP 文件

    ├── fgeduschema.fgedu02.sql

    └── ...

```

`unload` 是 `recover-all <datadir> <db>` 的语义化命令,必须指定用户名/数据库名,语义更明确,专为“按用户名 unload”场景设计。

#### 3.4.5 recover-directory - 按目录最大恢复

```bash

./fgogdu recover-directory <datadir> [-o outdir] [-f fmt]

```

此命令自动执行:

1. 导出所有数据库的所有表(含 LOB/TOAST 数据)

2. 包含已删除的数据行

3. 恢复 global/ 目录下的共享系统表

4. 扫描并导出孤立文件(DROP/TRUNCATE 的表)

5. 系统目录损坏时自动兜底恢复

输出目录结构:

```

/backup/recovery/

├── postgres_14448/

│   ├── public.orders.sql

│   ├── public.orders.dmp

│   ├── public.customers.sql

│   ├── _orphan/

│   │   └── orphan_12345.sql

│   └── ...

├── template1_1/

└── template0_14447/

```

#### 3.4.6 recover-file - 按数据文件恢复

```bash

./fgogdu recover-file <file> -s <schemafile> [name] [-o outdir] [-b blocksize] [--max]

```

参数说明:

- `<file>`:数据文件路径

- `-s <schemafile>`:模式文件路径(定义表结构)

- `[name]`:输出文件名(格式:schema.table)

- `-b <blocksize>`:强制指定块大小(默认自动检测)

示例:

```bash

./fgogdu recover-file /opengauss/data/base/14448/16384 \

  -s myschema.schema public.mytable -o /backup

```

#### 3.4.7 orphan-scan - 查找孤立文件

```bash

./fgogdu orphan-scan <datadir> <db>

```

扫描数据库目录中未被 pg_class 引用的数据文件(DROP/TRUNCATE 的表)。输出示例:

```

orphan (candidate dropped/truncated) files:

  /opengauss/data/base/14448/12345

  /opengauss/data/base/14448/12346

To recover one, build a .schema file and run:

  fgogdu recover-file <file> -s <schemafile> <schema.table>

```

### 3.5 通用选项

| 选项 | 说明 |

|------|------|

| `-o, --outdir <dir>` | 输出目录(默认 ./recover_out) |

| `-f, --format <fmt>` | 输出格式:sql / dmp / both(默认 both) |

| `-s, --schema-file <f>` | 手动模式文件(用于 recover-file) |

| `-b, --blocksize <n>` | 强制指定块大小(默认自动检测) |

| `--max` | 最大恢复:包含已删除数据,遇到错误继续 |

| `-v, --verbose` | 详细输出,显示更多诊断信息 |

### 3.6 输出格式说明

#### 3.6.1 SQL 格式(.sql)

每个表生成一个 SQL 文件,包含 `CREATE TABLE` 语句(自动还原表结构)与 `INSERT INTO` 语句(每行一条),已删除行有恢复标记注释:

```sql

-- FGOGDU export: public.orders

-- Source: openGauss data file (Astore heap)

-- Generated by FGOGDU v1.0

CREATE TABLE public.orders (

    id integer NOT NULL,

    customer_id integer,

    order_date timestamp,

    total_amount numeric,

    status character varying(20)

);

INSERT INTO public.orders (id, customer_id, order_date, total_amount, status)

  VALUES (1, 100, '2024-01-15 10:30:00', '199.99', 'pending');

-- recovered row blk=0 off=2 [was-deleted]

INSERT INTO public.orders (id, customer_id, order_date, total_amount, status)

  VALUES (2, 101, '2024-02-20 14:00:00', '299.50', 'shipped');

-- end of public.orders: 2 rows

```

#### 3.6.2 DMP 格式(.dmp)

自描述的二进制格式,包含:

- 文件头标识 `FGOGDUMP`

- 版本号、标志位

- 表名、列定义

- 每行数据的原始二进制值

- 恢复元数据(块号、偏移、删除状态)

DMP 格式保留原始二进制数据,适合程序化导入。

#### 3.6.3 特殊标记

| 标记 | 说明 |

|------|------|

| `<TOASTED>` | TOAST 表文件缺失或损坏,无法恢复 LOB 数据 |

| `<COMPRESSED>` | 内联压缩的 varlena 数据(非 TOAST),无法解压 |

| `[was-deleted]` | 该行为已删除但未被覆盖的数据 |

| `[partial]` | 该行部分列无法解码,以 NULL 填充 |

### 3.7 模式文件格式

用于 `recover-file` 命令手动指定表结构:

```

# 注释行以 # 开头

# 格式: 列名 类型 [NOT NULL]

# 类型可使用名称或数字 OID

# 列顺序必须与原表一致

id integer NOT NULL

name text

price numeric

created_at timestamp

data bytea

```

支持的类型名称:boolean、bytea、char、name、bigint/smallint/int8、smallint/int2、integer/int/int4、text、oid、real/float4、double/float8、bpchar/character、varchar/character varying、nvarchar2、date、time、timestamp、timestamptz、numeric、uuid、json、jsonb、xml。

---

## 四、程序各种案例场景与操作过程

### 场景一:openGauss数据库无法启动,全库一键导出

**背景**:openGauss 数据库因控制文件损坏、参数文件丢失或 redo 断裂等原因无法启动,需要尽快导出全部业务数据。

**操作步骤**:

```bash

# 1. 确认数据目录位置(应包含 base/、global/、pg_control 等)

ls /opengauss/data

# 2. 执行全库最大恢复

./fgogdu recover-directory /opengauss/data -o /backup/recovery

# 3. 查看恢复结果

ls /backup/recovery/

# postgres_14448/  template1_1/  template0_14447/

# 4. 查看某个数据库的恢复结果

ls /backup/recovery/postgres_14448/

# public.orders.sql  public.orders.dmp  public.customers.sql  ...

# 5. 恢复到新数据库

createdb newdb

psql -d newdb -f /backup/recovery/postgres_14448/public.orders.sql

```

**说明**:`recover-directory` 是应急场景下的首选命令,会自动执行全库导出、已删除数据恢复、孤立文件扫描、global/ 共享表恢复,并在系统目录损坏时自动兜底。

### 场景二:openGauss数据库无法启动,按用户(数据库)导出所有数据

**背景**:在 openGauss 中用户通常对应一个数据库,只需导出特定用户(数据库)的数据。

**操作步骤**:

```bash

# 1. 查看数据目录中有哪些数据库(用户)

./fgogdu databases /opengauss/data

# OID        NAME

# 14448      postgres

# 1          template1

# 14447      template0

# 2. 导出指定数据库(用户)的所有表数据

./fgogdu recover-all /opengauss/data postgres -o /backup --max

# 3. 也可使用 OID 导出

./fgogdu recover-all /opengauss/data 14448 -o /backup --max

# 4. 查看导出结果

ls /backup/postgres_14448/

# public.orders.sql  public.customers.sql  ...

# 5. 恢复到新数据库

psql -d newdb -f /backup/postgres_14448/public.orders.sql

```

也可使用语义更明确的 `unload` 命令按用户名导出所有表:

```bash

# 按用户名 unload,导出 fgedudb 下所有表(SQL + DMP)

./fgogdu unload /opengauss/data fgedudb -o /backup -f both

# 最大恢复模式(包含已删除数据)

./fgogdu unload /opengauss/data fgedudb -o /backup --max

```

### 场景三:openGauss数据库无法启动,按表精确导出数据

**背景**:仅需恢复特定的一个或几个表的数据。

**操作步骤**:

```bash

# 1. 查看数据库中有哪些表

./fgogdu tables /opengauss/data postgres

# OID        FILENODE   SCHEMA   TABLE    COLS

# 16384      16384      public   users    5

# 16385      16385      public   orders   8

# 2. 查看指定 schema 下的表

./fgogdu tables /opengauss/data postgres public

# 3. 恢复单个表

./fgogdu recover /opengauss/data postgres public orders -o /backup

# 4. 恢复单个表(包含已删除的数据)

./fgogdu recover-deleted /opengauss/data postgres public orders -o /backup

# 5. 恢复多个表(循环执行)

for table in orders customers products; do

  ./fgogdu recover /opengauss/data postgres public $table -o /backup

done

# 6. 恢复到新数据库

psql -d newdb -f /backup/public.orders.sql

```

### 场景四:openGauss数据库无法启动,直接按数据文件导出所有表数据

**背景**:系统目录损坏,无法通过表名定位表,需要直接从数据文件恢复。

**操作步骤**:

```bash

# 方式1:最大恢复模式,自动扫描所有数据文件(推荐)

./fgogdu recover-directory /opengauss/data -o /backup

# 方式2:恢复指定的单个数据文件(需手动提供表结构)

#   先创建模式文件:

cat > myschema.schema << 'EOF'

id integer NOT NULL

name text

content text

created_at timestamp

EOF

#   然后恢复:

./fgogdu recover-file /opengauss/data/base/14448/16384 \

  -s myschema.schema public.mytable -o /backup

# 方式3:查找孤立文件(被 DROP/TRUNCATE 的表)

./fgogdu orphan-scan /opengauss/data postgres

# orphan (candidate dropped/truncated) files:

#   /opengauss/data/base/14448/12345

# 方式4:恢复找到的孤立文件

./fgogdu recover-file /opengauss/data/base/14448/12345 \

  -s myschema.schema public.dropped_table -o /backup

```

### 场景五:openGauss DELETE 误删数据恢复

**背景**:误执行 DELETE 操作,需要恢复被删除的数据行。

**操作步骤**:

```bash

# 1. 立即停止数据库写入(防止被删除数据被新数据物理覆盖)

# 2. 恢复活跃+已删除数据

./fgogdu recover-deleted /opengauss/data postgres public orders -o /backup

# 3. 查看恢复结果,已删除的行标记为 [was-deleted]

grep "was-deleted" /backup/public.orders.sql

# -- recovered row blk=0 off=2 [was-deleted]

# INSERT INTO public.orders (...) VALUES (...);

# 4. 筛选出已删除的行(用于确认数据)

grep -A1 "was-deleted" /backup/public.orders.sql > /backup/deleted_rows.sql

# 5. 恢复到数据库(注意:需手动筛选需要的数据)

psql -d postgres -f /backup/public.orders.sql

```

**要点**:DELETE 删除的数据只有在未被新数据物理覆盖前才能恢复,因此误删后应立即停止数据库写入操作。

### 场景六:openGauss DROP/TRUNCATE 表恢复

**背景**:表被 DROP 或 TRUNCATE,系统目录中已无该表信息,但底层数据文件可能仍残留在磁盘上。

**操作步骤**:

```bash

# 1. 查找孤立文件

./fgogdu orphan-scan /opengauss/data postgres

# orphan (candidate dropped/truncated) files:

#   /opengauss/data/base/14448/12345

# 2. 创建模式文件(根据原表结构)

cat > orders.schema << 'EOF'

id integer NOT NULL

customer_id integer

order_date timestamp

total_amount numeric

status varchar(20)

EOF

# 3. 使用模式文件恢复

./fgogdu recover-file /opengauss/data/base/14448/12345 \

  -s orders.schema public.orders -o /backup

# 4. 恢复到新数据库

psql -d newdb -f /backup/public.orders.sql

```

**自动恢复**:使用 `recover-directory` 命令会自动扫描孤立文件并以原始格式导出:

```bash

./fgogdu recover-directory /opengauss/data -o /backup

```

### 场景七:openGauss LOB/大字段恢复

**背景**:表中包含 text、varchar、bytea 等大字段,数据存储在 TOAST 表中。

**说明**:FGOGDU 默认支持 LOB 恢复,无需额外参数。当变长字段超过约 2KB 时,openGauss 会将其存储到 TOAST 表中,FGOGDU 会自动读取 TOAST 表并重组数据。

**操作步骤**:

```bash

# 1. 恢复含大字段的表(LOB 自动恢复)

./fgogdu recover /opengauss/data postgres public documents -o /backup

# 2. 查看恢复结果(大字段数据已完整导出)

head -50 /backup/public.documents.sql

# CREATE TABLE public.documents (

#     id integer NOT NULL,

#     title varchar(200),

#     content text,

#     attachment bytea

# );

# INSERT INTO public.documents (id, title, content, attachment) VALUES

#   (1, 'doc1', '这是一段很长的文本内容...', '\x89504E47...');

# 3. 全库恢复(所有表的 LOB 数据都会自动恢复)

./fgogdu recover-directory /opengauss/data -o /backup

# 4. 验证 LOB 数据完整性

#   SQL 文件中:text/varchar 以引号字符串形式存储

#   SQL 文件中:bytea 以 '\x' 十六进制形式存储

#   DMP 文件中:以原始二进制形式存储

```

### 场景八:openGauss系统目录损坏时的兜底恢复

**背景**:系统目录(pg_database、pg_class)因坏块无法读取。

**操作步骤**:

```bash

# 1. 使用最大恢复模式(自动处理系统目录损坏)

./fgogdu recover-directory /opengauss/data -o /backup

# 2. 查看恢复日志

#   如果 pg_database 损坏,会看到:

#   WARNING: pg_database catalog unreadable; falling back to direct base/ directory scan

#

#   如果 pg_class 损坏,会看到:

#   pg_class unreadable for dboid XXXX; performing raw file scan (no schema).

# 3. 查看恢复结果

#   系统目录损坏时,数据以原始元组形式导出到 _orphan/ 目录

ls /backup/postgres_14448/_orphan/

# orphan_12345.sql  orphan_12346.sql  ...

# 4. 查看原始元组数据

head -20 /backup/postgres_14448/_orphan/orphan_12345.sql

# -- FGOGDU orphan recovery: /opengauss/data/base/14448/12345

# -- Block size: 8192

# -- No schema available (dropped/truncated table). Raw tuple dump.

# -- block=0 off=1 xmin=1000 xmax=0 natts=5 hoff=32 live

# -- raw(64 bytes): 0A000000...

```

**兜底策略**:

- pg_database 不可读 → 自动扫描 `base/` 下的数字子目录作为数据库 OID

- pg_class 不可读 → 对该库所有数据文件做无表结构的原始元组抽取

- 坏块自动跳过,继续恢复后续数据

### 场景九:openGauss坏块处理

**背景**:数据文件中部分数据页损坏。

**说明**:FGOGDU 在最大恢复模式下会自动跳过坏块,继续恢复后续数据。

**操作步骤**:

```bash

# 1. 使用最大恢复模式

./fgogdu recover /opengauss/data postgres public orders -o /backup --max

# 2. 查看哪些块被跳过(使用 verbose 模式)

./fgogdu recover /opengauss/data postgres public orders -o /backup --max -v

# 3. 诊断特定块

./fgogdu page /opengauss/data/base/14448/16384 5

# 如果输出 "block 5: not a valid page",说明该块损坏

# 4. 全库恢复时自动跳过坏块

./fgogdu recover-directory /opengauss/data -o /backup

```

### 场景十:openGauss指定输出格式

**背景**:只需 SQL 文件或只需 DMP 文件。

```bash

# 仅导出 SQL 文件

./fgogdu recover /opengauss/data postgres public orders -o /backup -f sql

# 仅导出 DMP 文件

./fgogdu recover /opengauss/data postgres public orders -o /backup -f dmp

# 同时导出两种格式(默认)

./fgogdu recover /opengauss/data postgres public orders -o /backup -f both

```

### 场景十一:openGauss按用户名 unload 导出所有表

**背景**:数据库无法启动,需按用户名(数据库)unload 导出该用户下所有表,要求显示详细的导出进度(表名、导出行数等)。

**操作步骤**:

```bash

# 1. 查看数据目录中的数据库(用户)列表

./fgogdu databases /opengauss/data

# OID        NAME

# 16385      fgedudb

# 2. 按用户名 unload,导出 fgedudb 下所有表(SQL + DMP),实时显示每表导出进度

./fgogdu unload /opengauss/data fgedudb -o /backup -f both

# 3. 最大恢复模式(包含已删除数据,遇到错误继续)

./fgogdu unload /opengauss/data fgedudb -o /backup --max

# 4. 查看导出结果

ls /backup/fgedudb/

# fgeduschema.fgedu01.sql  fgeduschema.fgedu01.dmp

# fgeduschema.fgedu02.sql  fgeduschema.fgedu02.dmp

# fgeduschema.fgedu_lob.sql  fgeduschema.fgedu_lob.dmp

# 5. 导入到新数据库

psql -d newdb -f /backup/fgedudb/fgeduschema.fgedu01.sql

```

**进度输出示例**(运行时实时显示):

```

[unload] database=fgedudb (oid=16385) outdir=/backup/fgedudb

[unload] scanning pg_class ... found 3 tables

[unload] exporting fgeduschema.fgedu01 ... 10 rows exported

[unload] exporting fgeduschema.fgedu02 ... 10 rows exported

[unload] exporting fgeduschema.fgedu_lob ... 3 rows exported (LOB recovered)

[unload] done. 3 tables, 23 rows total.

```

### 场景十二:openGauss多数据库批量恢复

**背景**:数据目录下有多个业务数据库,需要一次性导出全部。

**操作步骤**:

```bash

# 1. 查看所有数据库

./fgogdu databases /opengauss/data

# OID        NAME

# 14448      postgres

# 16385      fgedudb

# 16390      report_db

# 2. 一次性导出所有数据库(最大恢复模式)

./fgogdu recover-all /opengauss/data -o /backup --max

# 3. 查看恢复结果

ls /backup/

# postgres_14448/  fgedudb_16385/  report_db_16390/

```

### 场景十三:openGauss诊断数据页问题

**背景**:恢复结果异常,需要诊断具体数据页的状态。

**操作步骤**:

```bash

# 1. 检测数据文件块大小

./fgogdu blocksize /opengauss/data/base/14448/16384

# 8192

# 2. 查看第 0 页(首页)

./fgogdu page /opengauss/data/base/14448/16384 0

# block 0  size=8192 lower=48 upper=7920 special=8192 version=4

# lineptrs=6 normal=6 redirect=0 dead=0 unused=0 tuples=6

#   off=1  len=64   xmin=1000   xmax=0      natts=5  live

#   off=2  len=64   xmin=1001   xmax=2000   natts=5  del

# 3. 查看指定块(如怀疑第 5 块损坏)

./fgogdu page /opengauss/data/base/14448/16384 5 8192

# 如果输出 "block 5: not a valid page",说明该块损坏

# 4. 使用 verbose 模式恢复,查看跳过的坏块

./fgogdu recover /opengauss/data postgres public orders -o /backup --max -v

```

### 场景十四:openGauss恢复结果验证

**背景**:恢复完成后,需要验证数据完整性。

**操作步骤**:

```bash

# 1. 统计恢复的行数

grep -c "^INSERT" /backup/public.orders.sql

# 2. 查看恢复的表结构

grep "CREATE TABLE" /backup/public.orders.sql

# 3. 导入到新数据库验证

createdb testdb

psql -d testdb -f /backup/public.orders.sql

psql -d testdb -c "SELECT count(*) FROM public.orders;"

# 4. 对比源库与恢复库的行数(若源库可读)

# 源库:SELECT count(*) FROM public.orders;

# 恢复库:SELECT count(*) FROM public.orders;

```

### 场景十五:openGauss强制指定块大小

**背景**:自动检测块大小失败(如页头损坏),需手动指定。

**操作步骤**:

```bash

# 1. 尝试常见块大小(8192 最常见)

./fgogdu recover-file /opengauss/data/base/14448/16384 \

  -s myschema.schema public.mytable -o /backup -b 8192

# 2. 若 8192 失败,尝试 16384 / 32768 / 65536

./fgogdu recover-file /opengauss/data/base/14448/16384 \

  -s myschema.schema public.mytable -o /backup -b 16384

```

---

## 五、常用问题与排查

### 5.1 编译相关问题

#### 问题 1:编译报错 `找不到 -lstdc++` 或 `-lc` 或 `-lm`

**原因**:缺少静态链接库。

**解决**:安装静态链接库:

```bash

# RHEL/OEL/CentOS

dnf install glibc-static libstdc++-static

# Oracle Linux 需启用 CodeReady Builder 仓库

dnf config-manager --set-enabled ol9_codeready_builder

dnf install glibc-static libstdc++-static

```

#### 问题 2:编译报错 `g++: command not found`

**原因**:未安装编译器。

**解决**:

```bash

dnf install gcc gcc-c++ make

```

#### 问题 3:编译报错 `g++: error: unrecognized option '-std=c++17'`

**原因**:GCC 版本过低,不支持 C++17。

**解决**:升级 GCC 至 4.8 以上版本(建议 GCC 9+):

```bash

# RHEL 8/9

dnf install gcc-toolset-11

scl enable gcc-toolset-11 bash

```

### 5.2 运行环境问题

#### 问题 4:运行报错 `./fgogdu: /lib64/libc.so.6: version 'GLIBC_2.28' not found`

**原因**:在比编译机 glibc 版本更旧的目标服务器上运行静态链接二进制。

**解决**:在 glibc 版本更低的服务器上重新编译,或使用更旧的编译机进行编译。

#### 问题 5:运行报错 `Permission denied`

**原因**:对数据目录无读权限,或对输出目录无写权限。

**解决**:

```bash

# 确认对数据目录有读权限

ls -l /opengauss/data/base/

# 确认对输出目录有写权限

touch /backup/test && rm /backup/test

# 必要时使用具有权限的用户执行

sudo ./fgogdu recover-directory /opengauss/data -o /backup

```

### 5.3 恢复问题

#### 问题 6:`database not found: postgres`

**原因**:数据库名拼写错误,或数据目录路径不正确。

**解决**:

1. 确认数据目录路径正确

2. 使用 `databases` 命令查看可用数据库

3. 使用 OID 代替数据库名

```bash

./fgogdu databases /opengauss/data

./fgogdu recover /opengauss/data 14448 public orders -o /backup

```

#### 问题 7:`no relations discovered for dboid XXXX`

**原因**:该数据库的系统目录(pg_class)损坏,无法读取表信息。

**解决**:使用最大恢复模式,自动兜底处理:

```bash

./fgogdu recover-directory /opengauss/data -o /backup

```

#### 问题 8:恢复出的数据显示 `<TOASTED>`

**原因**:TOAST 表文件缺失或损坏。可能原因:

1. TOAST 表文件被删除

2. TOAST 表数据文件损坏

3. reltoastrelid 在 pg_class 中不可读

**解决**:使用 `recover-directory` 命令进行最大恢复,它会尝试所有可能的恢复路径。若 TOAST 文件已物理丢失,则该 LOB 字段无法恢复,但其他字段与其他行不受影响。

#### 问题 9:恢复出的数据显示 `<COMPRESSED>`

**原因**:该值使用了内联压缩(非 TOAST 压缩),FGOGDU 目前不支持内联压缩的解压。通常发生在较老的 PostgreSQL 版本中。

**解决**:此类数据暂无法通过 FGOGDU 解压恢复,可尝试使用其他专业工具。

#### 问题 10:恢复行数少于预期

**可能原因**:

1. 部分数据页损坏(坏块),被自动跳过

2. 部分数据行已被物理覆盖(DELETE 后被新数据覆盖)

3. 表存在分区,未恢复到所有分区文件

4. 使用了 `recover` 而非 `recover-deleted`,未包含已删除数据

**排查步骤**:

```bash

# 1. 使用 verbose 模式查看跳过的坏块

./fgogdu recover /opengauss/data postgres public orders -o /backup --max -v

# 2. 包含已删除数据

./fgogdu recover-deleted /opengauss/data postgres public orders -o /backup

# 3. 诊断特定数据页

./fgogdu page /opengauss/data/base/14448/16384 0

# 4. 使用最大恢复模式兜底

./fgogdu recover-directory /opengauss/data -o /backup

```

#### 问题 11:`block N: not a valid page`

**原因**:指定块损坏或块大小不正确。

**解决**:

```bash

# 1. 检测正确的块大小

./fgogdu blocksize /opengauss/data/base/14448/16384

# 2. 用正确块大小查看

./fgogdu page /opengauss/data/base/14448/16384 5 8192

# 3. 若确实损坏,使用 --max 模式跳过坏块继续恢复

./fgogdu recover /opengauss/data postgres public orders -o /backup --max

```

#### 问题 12:恢复出的表结构缺失列或列顺序错误

**原因**:系统目录中 pg_attribute 信息部分损坏。

**解决**:

1. 使用 `page` 命令查看元组的 `natts`(实际列数)

2. 根据业务知识手动编写模式文件

3. 使用 `recover-file` 命令按手动模式恢复

```bash

./fgogdu page /opengauss/data/base/14448/16384 0

# 查看 natts=X,确定列数

cat > mytable.schema << 'EOF'

id integer NOT NULL

name varchar(50)

...

EOF

./fgogdu recover-file /opengauss/data/base/14448/16384 \

  -s mytable.schema public.mytable -o /backup

```

#### 问题 13:`unload` 命令报 `database not found`

**原因**:`unload` 必须指定用户名/数据库名,且该名称需与 `databases` 命令输出的名称一致。

**解决**:

```bash

# 先查看可用数据库名

./fgogdu databases /opengauss/data

# 再用正确的名称 unload

./fgogdu unload /opengauss/data fgedudb -o /backup -f both

```

### 5.4 数据验证问题

#### 问题 14:导入 SQL 文件时报语法错误

**可能原因**:

1. 恢复的数据中包含特殊字符(如单引号未正确转义)

2. 表结构与目标库不兼容(如类型差异)

3. 恢复过程中部分行部分列解码失败

**排查**:

```bash

# 1. 查看出错的行

psql -d newdb -f /backup/public.orders.sql 2>&1 | grep ERROR

# 2. 查看是否有 [partial] 标记的行

grep "partial" /backup/public.orders.sql

# 3. 检查特殊字符

grep -n "\\\\" /backup/public.orders.sql | head

```

#### 问题 15:DMP 文件无法导入

**原因**:DMP 是 FGOGDU 自定义的二进制格式,需使用配套的导入工具,不兼容 gs_dump/pg_dump 的 DMP 格式。

**解决**:优先使用 SQL 格式导入(`-f sql`),或使用配套的 DMP 导入程序。

### 5.5 性能问题

#### 问题 16:恢复速度慢

**优化建议**:

- 使用 `-f sql` 或 `-f dmp` 只导出一种格式,减少 I/O

- 对于大型数据库,使用 `recover-all` 或 `recover-directory` 而非逐表恢复

- 输出目录建议使用高速磁盘(SSD/NVMe)

- LOB 恢复会增加内存使用,单 LOB 上限 256MB

- 在内存充足的服务器上运行,避免因内存不足导致频繁 swapping

### 5.6 故障排查通用流程

当恢复结果与预期不符时,建议按以下流程排查:

1. **确认数据目录路径**:`ls /opengauss/data`,应看到 base/、global/、pg_control 等。

2. **查看可用数据库**:`./fgogdu databases <datadir>`,确认目标数据库存在。

3. **查看表列表**:`./fgogdu tables <datadir> <db>`,确认目标表存在且列数正确。

4. **诊断数据页**:`./fgogdu page <file> 0`,查看首页结构与元组状态。

5. **使用 verbose + max 模式恢复**:`./fgogdu recover ... --max -v`,查看详细日志与跳过的坏块。

6. **对比行数**:统计恢复的 INSERT 行数,与源库(若可读)对比。

7. **兜底恢复**:若以上均不理想,使用 `recover-directory` 进行最大恢复兜底。

---

## 六、附录

### 6.1 命令速查表

| 场景 | 命令 |

|------|------|

| 查看版本 | `fgogdu version` |

| 查看帮助 | `fgogdu help` |

| 查看数据库 | `fgogdu databases <datadir>` |

| 查看模式 | `fgogdu schemas <datadir> <db>` |

| 查看表 | `fgogdu tables <datadir> <db> [schema]` |

| 检测块大小 | `fgogdu blocksize <file>` |

| 诊断数据页 | `fgogdu page <file> <blkno> [blocksize]` |

| 恢复单表 | `fgogdu recover <datadir> <db> <schema> <table> -o <outdir>` |

| 恢复已删除 | `fgogdu recover-deleted <datadir> <db> <schema> <table> -o <outdir>` |

| 按数据库导出 | `fgogdu recover-all <datadir> <db> -o <outdir> --max` |

| 按用户名 unload | `fgogdu unload <datadir> <db> -o <outdir> -f both [--max]` |

| 全库导出 | `fgogdu recover-all <datadir> -o <outdir> --max` |

| 一键最大恢复 | `fgogdu recover-directory <datadir> -o <outdir>` |

| 按文件恢复 | `fgogdu recover-file <file> -s <schemafile> <name> -o <outdir>` |

| 查找孤立文件 | `fgogdu orphan-scan <datadir> <db>` |

### 6.2 选项速查表

| 选项 | 说明 |

|------|------|

| `-o, --outdir <dir>` | 输出目录(默认 ./recover_out) |

| `-f, --format <fmt>` | 输出格式:sql / dmp / both(默认 both) |

| `-s, --schema-file <f>` | 手动模式文件(用于 recover-file) |

| `-b, --blocksize <n>` | 强制指定块大小(默认自动检测) |

| `--max` | 最大恢复:包含已删除数据,遇到错误继续 |

| `-v, --verbose` | 详细输出 |

### 6.3 特殊标记速查表

| 标记 | 说明 |

|------|------|

| `<TOASTED>` | TOAST 表文件缺失或损坏,无法恢复 LOB 数据 |

| `<COMPRESSED>` | 内联压缩的 varlena 数据(非 TOAST),无法解压 |

| `[was-deleted]` | 该行为已删除但未被覆盖的数据 |

| `[partial]` | 该行部分列无法解码,以 NULL 填充 |

### 6.4 项目结构

```

FGOGDU/

├── src/

│   ├── common.h       # 公共定义:页结构、常量、工具函数

│   ├── types.h        # 类型定义:OID枚举、列定义、值结构、ToastResolver

│   ├── types.cpp      # 类型解码:varlena、numeric、日期时间、pglz解压、TOAST解析

│   ├── page.h         # 页面解析器接口

│   ├── page.cpp       # 页面解析实现:块大小检测、页头验证、元组提取

│   ├── relation.h     # 关系模型:Schema、RecoveredRow、文件读取

│   ├── relation.cpp   # 元组解码、关系文件扫描

│   ├── catalog.h      # 系统目录读取器接口

│   ├── catalog.cpp    # 系统目录解析:pg_database、pg_class、pg_attribute

│   ├── recovery.h     # 恢复操作接口

│   ├── recovery.cpp   # 恢复实现:单表、全库、孤立文件、TOAST/LOB恢复

│   ├── exporter.h     # 导出器接口

│   ├── exporter.cpp   # SQL/DMP 导出实现

│   ├── commands.h     # 命令分发接口

│   ├── commands.cpp   # 命令行解析和执行

│   └── main.cpp       # 程序入口

├── docs/

│   └── README-WEB.md  # 本说明手册

├── Makefile           # 编译规则(静态链接)

├── build.sh           # 一键编译脚本

├── README.md          # 项目 README

├── usage_manual.md    # 详细使用手册

└── testdoc.md         # 实验测试手册

```

### 6.5 许可证

FGEDU(FG Education)内部工具,仅供内部数据恢复与应急演练使用。

作者:风哥

官方网站: http://www.fgedu.net.cn ,  http://www.itpux.com

数据库教程:  https://edu.51cto.com/lecturer/8020378.html