内容提要
PostgreSQL中DROP TABLE后无备份恢复极难。PG数据块不含表OID,需通过表结构字段顺序匹配定位目标数据块,再用PDU工具解析导出。当前无法区分同结构表,大磁盘扫描速度受限,未来将用inode和块级扫描优化。
延伸解读
PG数据块定位的巧妙思路
文章指出,PostgreSQL数据块不包含表OID,因此无法像其他数据库那样直接定位。作者通过数据块头部固定字段(如pd_special和pd_pagesize_version)识别PG数据块,再依据表结构字段顺序和长度匹配来筛选目标数据块。这种基于结构特征的方法,为无备份恢复提供了可行路径。
恢复过程中的实际限制
当前方法存在两个主要局限:一是无法区分同结构的不同表,因为仅依赖字段顺序和长度匹配;二是全盘扫描速度慢,因为需逐块检查。文章提到未来计划使用inode区分文件,以及块级扫描优化性能,但尚未实现,用户需注意恢复的时效性和准确性风险。
操作系统的“伪删除”是恢复前提
DROP TABLE在操作系统层面通常只是截断文件,并未立即擦除物理数据,这为恢复提供了可能。但数据块被标记为可重用,若被新数据覆盖则无法恢复。因此,恢复操作应尽快进行,并避免对磁盘进行大量写入,以提高成功率。
Q&A
PostgreSQL中执行DROP TABLE后,数据是否立即从磁盘上物理删除?
不是。DROP TABLE在操作系统层面通常只是调用truncate函数清空文件,但磁盘上的实际数据块并未立即被清零,而是被标记为可重用,物理数据仍然存在,直到被新数据覆盖。
为什么PostgreSQL数据块中不包含表OID,这对恢复有什么影响?
PostgreSQL数据块头中不存储表文件OID,因此无法像Oracle、MySQL等数据库那样直接通过表ID定位目标数据块。这导致恢复时必须依赖表结构字段顺序匹配来识别数据块,增加了恢复难度。
PDU如何识别磁盘上的PostgreSQL数据块?
PDU通过检查数据页的pd_special值(应为8192)和pd_pagesize_version值(应为8196)来识别PG数据块。这两个字段在普通表中具有固定值,可作为识别标志。
在没有表OID的情况下,PDU如何定位目标表的数据块?
PDU利用表结构字段顺序进行匹配。首先对数据块中的记录按字段类型解析,对于结构类型(如varchar、numeric等)设置校验门限,然后比较解析出的记录长度与数据页中存储的lp_len是否一致,若一致则认为是目标数据块。
PDU的碎片扫描恢复功能目前存在哪些限制?
主要限制有两个:一是无法区分具有相同结构的表,因为识别依赖表结构;二是大磁盘扫描速度受限,因为需要以最小粒度扫描磁盘。未来计划使用inode区分同结构表,并采用块级扫描优化速度。
DROP TABLE后,恢复出的数据文件为什么是“匿名”的?如何重新导入?
因为DROP TABLE会从系统目录(如pg_class、pg_attribute)中删除表结构定义,导致恢复出的数据文件没有表结构信息。需要先创建一个结构完全一致的新表,然后使用PDU解析数据文件并导入。