仅靠/var/lib/postgresql/9.5/main/base/目录如何恢复PostgreSQL数据库?
嘿,我明白你现在的处境——手里只有/var/lib/postgresql/9.5/main/base/下的几个子目录,没有完整备份,要恢复16385路径对应的数据库。先给你打个底:这种恢复属于应急冷恢复,有一定风险(毕竟缺了全局系统表的元数据),但咱们一步步来,尽量把数据救回来。
第一步:先搞清楚目标目录的身份
16385是PostgreSQL数据库的OID(对象标识符),正常情况下pg_database系统表会记录OID和数据库名的映射,但你现在没有全局系统表数据,所以先默认这个目录就是你要恢复的目标库,后续启动后再确认细节。
第二步:搭一个完全匹配的PostgreSQL 9.5环境
必须用和原环境完全相同版本的PostgreSQL 9.5(连小版本都要尽量一致,比如9.5.25),因为不同版本的数据文件格式不兼容。
- 先停掉新实例的服务:
sudo systemctl stop postgresql - 清空新实例的base目录(记得先备份新实例的原始数据,别误删有用的东西):
sudo rm -rf /var/lib/postgresql/9.5/main/base/*
第三步:复制目标目录到新实例的base路径
把你手里的16385目录复制到新实例的base目录下,权限一定要改对——PostgreSQL的数据目录必须属于postgres用户:
# 替换/path/to/your/16385为你实际的16385目录路径 sudo cp -r /path/to/your/16385 /var/lib/postgresql/9.5/main/base/ sudo chown -R postgres:postgres /var/lib/postgresql/9.5/main/base/16385 sudo chmod -R 700 /var/lib/postgresql/9.5/main/base/16385
划重点:你手里还有151785、16386、13687这几个目录,大概率是系统表或依赖对象的存储目录,最好也一起复制过去,不然启动时可能会因为缺依赖报错。
第四步:手动修复数据库的系统映射(最关键的一步)
新实例的pg_database表里没有16385这个OID的记录,直接启动会找不到这个数据库,所以得手动加进去:
- 启动PostgreSQL到单用户模式(这一步能避免服务启动后直接崩溃):
sudo -u postgres postgres --single -D /var/lib/postgresql/9.5/main postgres - 在单用户模式下执行SQL,添加数据库记录(这里假设你要恢复的数据库名叫
target_db,后续可以改,先填个临时名就行):INSERT INTO pg_database (datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit, datlastsysoid, datfrozenxid, datminmxid, dattablespace, datacl) VALUES ('target_db', 10, 6, 'en_US.UTF-8', 'en_US.UTF-8', false, true, -1, 13687, 1, 1, 1663, '{=Tc/postgres,postgres=CTc/postgres}');简单解释下参数:
datdba:数据库所有者,通常是postgres用户,OID固定为10encoding:6对应UTF-8,你可以根据原数据库的编码调整(如果记得的话)datcollate/datctype:排序规则,填原环境的对应值,这里用UTF-8默认值dattablespace:默认表空间OID是1663(pg_default)datlastsysoid:填你手里的13687,这个是系统表的OID
- 输入
\q退出单用户模式。
第五步:启动服务并验证恢复结果
启动PostgreSQL服务:
sudo systemctl start postgresql
然后登录到PostgreSQL,试试能不能访问目标数据库:
sudo -u postgres psql -d target_db
如果能成功登录,就可以检查表和数据了:
\dt -- 列出所有表 SELECT * FROM your_table_name; -- 替换成你的表名,检查数据是否存在
常见问题排查
- 权限报错:检查所有复制过来的目录和文件,所有者必须是
postgres,目录权限700,文件权限600。 - 启动时提示缺少文件:把你手里的其他几个目录(151785、16386、13687)也复制到base目录下,改好权限再试。
- 部分表无法访问:可能是数据文件损坏,这种情况下优先用
pg_dump导出能正常访问的表,然后重建干净的数据库再导入。
重要提醒
这种恢复方式是无完整备份时的应急手段,没法保证100%恢复所有数据(尤其是元数据可能有缺失)。恢复成功后,一定要立刻用pg_dump把整个数据库导出,然后重建一个干净的PostgreSQL实例,再导入数据,避免后续出现稳定性问题。
内容的提问来源于stack exchange,提问作者user3752051

