说到 PostgreSQL 的数据迁移,很多人第一反应是“把文件拷过去就行”。但实际操作中,如果漏掉几个关键步骤,轻则服务起不来,重则数据损坏。这里把完整流程拆开揉碎,从头到尾过一遍。

1. 停止 PostgreSQL 服务
动手之前,先确保数据库已经完全停止,不能有任何活跃连接。否则直接操作数据目录,后果很难预料。
# 使用 systemctl(如果已配置) systemctl stop postgresql-15 # 或直接使用 postmaster kill -INT $(head -1 /var/lib/pgsql/15/data/postmaster.pid) # 或使用 pg_ctl /usr/pgsql-15/bin/pg_ctl stop -D /var/lib/pgsql/15/data/
2. 创建新数据目录
确定好目标路径后,先建好目录,然后调整权限。这一步容易忽略的是:目录的所有者必须是 postgres,权限必须为 700,否则启动时会直接报错。
# 例如移动到 /data/pgsql 目录 NEW_DATA_DIR="/data/pgsql/15/data" # 创建新目录 mkdir -p "$NEW_DATA_DIR" # 设置正确的权限(postgres 用户) chown -R postgres:postgres "$NEW_DATA_DIR" chmod 700 "$NEW_DATA_DIR"
3. 复制(或移动)数据文件
建议直接使用 mv,因为数据量大时复制耗时很长,且移动操作不会产生双倍空间占用。如果对原数据有顾虑,可以先用 cp -rp 复制一份,等确认新目录运行正常后再清理原目录。
# 方法1:移动数据(推荐,更快) mv /var/lib/pgsql/15/data/* "$NEW_DATA_DIR/" # 方法2:复制数据(保留原数据) cp -rp /var/lib/pgsql/15/data/* "$NEW_DATA_DIR/"
4. 修改配置文件
这一步有两种思路:要么直接在 postgresql.conf 中更新 data_directory 参数,要么通过软链接“欺骗”系统。后者适合不想修改配置文件、或者需要快速回退的场景。
方法A:修改 postgresql.conf
# 编辑配置文件 vi "$NEW_DATA_DIR/postgresql.conf" # 修改或添加以下行 data_directory = '/data/pgsql/15/data'
方法B:使用软链接(不修改配置文件)
# 备份原目录 mv /var/lib/pgsql/15/data /var/lib/pgsql/15/data_old # 创建软链接 ln -s /data/pgsql/15/data /var/lib/pgsql/15/data # 确保权限正确 chown -R postgres:postgres /var/lib/pgsql/15/data
5. 启动 PostgreSQL
启动方式和之前对应。如果用了 systemctl,之前停的服务现在直接启动即可。如果习惯手动操作,用 pg_ctl 或 postmaster 也一样。
# 使用 systemctl systemctl start postgresql-15 # 或直接启动 /usr/pgsql-15/bin/postmaster -D "$NEW_DATA_DIR" & # 或使用 pg_ctl /usr/pgsql-15/bin/pg_ctl start -D "$NEW_DATA_DIR"
6. 验证
启动后别急着走,先确认一下数据目录是否真的指向了新路径。
# 检查数据目录 /usr/pgsql-15/bin/psql -h localhost -p 30004 -U postgres -c "SHOW data_directory;" # 查看当前配置 /usr/pgsql-15/bin/psql -h localhost -p 30004 -U postgres -c "SELECT * FROM pg_settings WHERE name LIKE '%data_directory%';"
7. 更新 systemd 服务文件(如果使用 systemctl)
如果启动服务依赖 systemctl,且启动命令中没有显式指定 -D 参数,就需要在服务文件中更新 PGDATA 环境变量。否则重启后服务还是会去找原来的路径。
# 编辑服务文件 vi /etc/systemd/system/postgresql-15.service # 或编辑 override 文件 mkdir -p /etc/systemd/system/postgresql-15.service.d cat > /etc/systemd/system/postgresql-15.service.d/override.conf << EOF [Service] Environment=PGDATA=/data/pgsql/15/data EOF # 重新加载 systemd systemctl daemon-reload
完整脚本示例
如果觉得手动一步步操作太麻烦,可以直接用下面的脚本。它把停止、迁移、配置、启动和验证串在了一起,省心不少。
#!/bin/bash # 配置 OLD_DATA="/var/lib/pgsql/15/data" NEW_DATA="/data/pgsql/15/data" PG_VERSION="15" PG_USER="postgres" # 1. 停止 PostgreSQL echo "停止 PostgreSQL..." /usr/pgsql-15/bin/pg_ctl stop -D "$OLD_DATA" -m fast # 2. 创建新目录 echo "创建新数据目录..." mkdir -p "$NEW_DATA" chown -R $PG_USER:$PG_USER "$NEW_DATA" chmod 700 "$NEW_DATA" # 3. 移动数据 echo "迁移数据文件..." rsync -a v --progress "$OLD_DATA/" "$NEW_DATA/" # 验证后可以删除原数据 # rm -rf "$OLD_DATA" # 4. 更新配置 echo "更新配置文件..." sed -i "s|data_directory = .*|data_directory = '$NEW_DATA'|" "$NEW_DATA/postgresql.conf" # 5. 启动 PostgreSQL echo "启动 PostgreSQL..." /usr/pgsql-15/bin/pg_ctl start -D "$NEW_DATA" # 6. 验证 echo "验证数据目录..." /usr/pgsql-15/bin/psql -h localhost -p 30004 -U postgres -c "SHOW data_directory;" echo "迁移完成!"
注意事项
有几个坑需要提前防住:
- 磁盘空间:迁移前先确认目标目录有足够空间,尤其是用复制操作时,原目录和新目录会同时存在,空间占用翻倍。
- 权限:数据目录必须属于
postgres用户,权限为700。这个检查一下就能避免很多启动问题。 - SELinux:如果系统开启了 SELinux,需要手动放行新的数据目录路径。
semanage fcontext -a -t postgresql_db_t "/data/pgsql(/.*)?" restorecon -Rv /data/pgsql
- 防火墙:如果在新环境中改动了端口,别忘了更新防火墙规则。
检查当前数据目录
如果某天忘了数据目录到底在哪,可以用下面几种方式快速定位:
# 方法1:通过 SQL /usr/pgsql-15/bin/psql -h localhost -p 30004 -U postgres -c "SHOW data_directory;" # 方法2:查看进程 ps aux | grep postmaster | grep -E "-D" # 方法3:查看配置文件 grep data_directory /var/lib/pgsql/15/data/postgresql.conf
以上就是更改 PostgreSQL 数据存储位置的完整流程。关键点无非是停服务、搬文件、改配置、启动验证,每一步都别跳,确保无误后再投入生产环境。
