pg_dump与pg_restore恢复后数据库体积减半原因咨询
我有一个磁盘占用93GB的PostgreSQL数据库,使用pg_dump和pg_restore将其备份恢复至另一台PostgreSQL服务器,操作步骤如下:
原数据库信息
# 原数据库磁盘占用为93GB root@dev-postgres-0:/# du -sh /var/lib/postgresql/data/ 93G /var/lib/postgresql/data/ root@dev-postgres-0:/#
方法一:Tar格式备份恢复
备份操作
root@test-postgres-0:/home/postgres/pgdata# pg_dump -U test_admin -h 10.44.5.10 -p 5432 -F t test > test.tar root@test-postgres-0:/home/postgres/pgdata# ls test.tar lost+found pgroot root@test-postgres-0:/home/postgres/pgdata#.
备份文件大小
root@fx-postgres-0:/home/postgres/pgdata# du -sh test.tar 76G test.tar root@fx-postgres-0:/home/postgres/pgdata#
恢复操作
root@test-postgres-0:/home/postgres# pg_restore -U test_admin -d test test.tar root@test-postgres-0:/home/postgres#
恢复后数据库目录大小
root@test-postgres-0:/home/postgres/pgdata# du -sh pgroot/ 45G pgroot/ root@test-postgres-0:/home/postgres/pgdata#
方法二:SQL格式备份恢复
备份操作
root@test-postgres-0:/home/postgres/pgdata# pg_dump -U test_admin -h 10.44.5.10 -p 5432 test > test.sql root@test-postgres-0:/home/postgres/pgdata# ls test.sql lost+found pgroot root@test-postgres-0:/home/postgres/pgdata#.
备份文件大小
root@fx-postgres-0:/home/postgres/pgdata# du -sh test.sql 76G test.sql root@fx-postgres-0:/home/postgres/pgdata#
恢复操作
root@test-postgres-0:/home/postgres/pgdata# psql -U test_admin test < test.sql root@test-postgres-0:/home/postgres/pgdata#
恢复后数据库目录大小
root@test-postgres-0:/home/postgres/pgdata# du -sh pgroot/ 45G pgroot/ root@test-postgres-0:/home/postgres/pgdata#
尽管备份恢复过程无报错,但恢复后的数据库目录仅占用45GB,约为原数据库的一半。请问该现象的原因是什么?是否遗漏了某些操作以恢复完整体积?
这种现象是正常的,并非遗漏操作,核心原因如下:
原数据库存在大量未回收的空闲空间
原数据库的93GB目录包含大量空闲空间:比如执行删除、更新操作后,PostgreSQL不会立刻释放磁盘空间,只会标记这些空间为“可复用”,供后续数据写入使用。而pg_dump只导出实际存在的有效数据,不会包含这些空闲空间,因此恢复后的数据库会自动清理这些无用空间,磁盘占用自然缩小。数据碎片化被消除
原数据库长期运行过程中,频繁的写入、更新、删除会导致数据存储碎片化——同一个表的数据可能分散在多个磁盘块中。通过pg_dump导出再恢复的过程,相当于重新组织了数据存储结构,让数据更紧凑地排列,消除了碎片化带来的额外磁盘占用。备份格式不影响最终恢复大小
两种备份格式(Tar和SQL)恢复后的大小一致,说明两种方式都正确导出了所有有效数据,备份格式的差异只会影响备份文件本身,和恢复后的数据库实际占用空间无关。
验证数据完整性的方法
若担心数据不完整,可通过以下方式确认:
- 对比核心表的行数:对关键表执行
SELECT COUNT(*) FROM table_name;,确保原库和恢复库的行数一致。 - 校验关键数据哈希:对重要表的数据集生成哈希值(例如
SELECT md5(CAST((array_agg(table_name ORDER BY id)) AS text)) FROM table_name;),对比两边结果。 - 运行业务测试:通过实际业务操作验证功能正常、数据无误。
是否需要恢复到原大小?
不需要。恢复后的45GB是实际数据的真实占用空间,原库的93GB包含大量可复用的空闲空间,这些空间在恢复后的数据库中会随着后续数据写入自动被利用,完全不影响数据库正常运行。强行让恢复后的数据库占用和原库一样的空间,反而会浪费磁盘资源。
内容的提问来源于stack exchange,提问作者devops-admin

