ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PostgreSQL数据导入导出实战:pg_dump与pg_restore全流程详解

PostgreSQL数据导入导出实战:pg_dump与pg_restore全流程详解 用过 PostgreSQL 的人一定逃不过这么一幕给客户部署新环境要把旧库里的业务数据倒过去或者数据库版本要升级从 12 一路追到 16、17再或者就是日常备份哪天服务器突然挂了只能靠备份捞数据。我在后端和数据这条线上干了十几年说实话PostgreSQL 数据导入导出是我用得最频繁的“救火技能”没有之一。这套命令玩得顺不顺直接决定你在故障面前是优雅恢复还是加班到半夜。这篇就按我自己的实操复盘来写。不只会丢几条命令而是把工具选型、导出格式、恢复命令、跨环境迁移、Docker 容器操作、大数据量调优这些环节串成一条线。刚装好 PostgreSQL 不知道怎么把数据倒进去的新手可以从头看到尾已经用了一阵、想搞清楚 pg_dump 各种参数怎么配的老手也能直接在文里找到能落地的东西。版本选择上我也多说一句日常使用跟着官方稳定版走就行但导入导出的工具版本要贴合你正在用的库版本这事比追新更重要后面会展开讲。1. 先把工具和格式搞清楚导入导出不是一条命令解决所有事1.1 工具全家桶pg_dump、pg_restore、psql、pgAdmin 各管哪一段很多人刚开始接触 PostgreSQL 导入导出只会记一条 pg_dump然后其他全靠临时搜索。这样做不是不行但一旦遇到“只要某个表”“跨版本恢复”“容器里导出”这种变体场景就容易卡住。我的建议是先建立一张工具地图。pg_dump 是逻辑备份的核心工具负责把数据库里的表、索引、视图、函数、触发器这些对象和行数据转成一份独立的备份文件。它导出的不是磁盘上的物理文件拷贝而是“数据内容结构定义”所以备份文件可以在不同架构、不同版本、甚至不同操作系统之间来回搬。pg_dumpall 则是把整个 PostgreSQL 实例打包导出除了各数据库还会带上角色、表空间这类全局对象做实例级容灾时会用到。pg_restore 专门用来把自定义格式custom 或 directory 格式的备份恢复到目标库它比 psql 灵活得多能按表、按 schema 选择性恢复也能并行恢复。psql 虽然主要是日常执行的交互终端但它是 SQL 脚本导入的入口数据文件也能通过 \copy 进库。pgAdmin 是图形化管理工具提供右键导入导出向导适合不想碰命令行的场景但生产环境批量操作时效率不高。第三方工具里 Navicat for PostgreSQL 我偶尔也用主要图它界面直观但大数据量或精细迁移时还是命令行可控性更强。1.2 四种导出格式各自适配哪些场景pg_dump 的 -F 参数确定输出格式我用得最多的是 custom-Fc和 plain默认。plain 格式就是纯 SQL 文本结构清晰可读也能直接交给 psql 执行适合小库、审计、或者需要手动改一改再导入的场景。但它的问题也很明显恢复是顺序执行大库恢复极慢也不能做选择性恢复。custom 是压缩后的二进制格式pg_restore 可以挑单个表恢复可以做并行恢复还自带压缩体积小这是我最推荐的日常备份格式生产环境默认选它。directory 格式会生成一个目录每个表单独一个文件配合 -j 参数可以并行导出和恢复对超大库几百 GB 甚至上 TB特别友好。tar 格式其实用得少了它把多个文件打成一个 tar 包兼容性和灵活性介于 plain 和 custom 之间但没有 custom 的压缩和并行能力我基本只在需要和外部系统对接时才用。选格式不是随便定的它直接影响后面恢复的效率和灵活度。我一般按场景这么选手头没想好什么时候恢复、可能要长期留着的备份用 custom 或 directory要交付给其他人并在另一个环境里执行不确定对方环境优先给 plain SQL表数量特别多、单表数据量特别大的库用 directory 并行环境紧张想省磁盘custom 加高压缩级别是个好选择。1.3 工具与格式的搭配速查表这个表我贴在工位上过一段时间后来才发现其实用顺手了根本不用看但新手阶段对建立直觉很有帮助。目的推荐工具推荐格式备注单库日常备份pg_dump pg_restorecustom压缩好、可选择性恢复实例级备份pg_dumpallplain含角色、表空间等全局对象跨版本迁移pg_dump pg_restorecustom 或 plain注意客户端版本匹配只要结构pg_dump --schema-onlyplain复制建表脚本只要数据pg_dump --data-onlycustom 或 plain配合 pg_restore 或 psql超大库迁移pg_dump -Fd -jdirectory并行导出恢复时也能并行Docker 内备份docker exec pg_dumpcustom再 docker cp 出来2. 备份导出实操从单表到全库的 pg_dump 用法2.1 按范围拆解导出全库、单表、按 schema、按条件最基础的导出命令长这样pg_dump -h 127.0.0.1 -p 5432 -U postgres -d mydb -F c -f /backup/mydb.dump-h 指定主机-p 指定端口-U 指定用户-d 指定库名-F c 指定 custom 格式-f 指定输出文件。这里有个高频坑新手经常把 -p 当成密码参数。不是的-p 是端口密码要么交互输入要么用 PGPASSWORD 环境变量要么配 .pgpass 文件。我日常会写类似 PGPASSWORDxxx pg_dump ... 的写法一次性执行方便但要注意 shell 历史记录里会留下密码生产环境不要这么搞。只看某几个表用 -t 参数pg_dump -U postgres -d mydb -t public.users -t public.orders -F c -f users_orders.dump只看某个 schema用 -npg_dump -U postgres -d mydb -n sales -F c -f sales_schema.dump只导出数据不要结构加 --data-only只导出结构不要数据加 --schema-only。这两个参数在搭建测试环境时特别有用——先拿 --schema-only 建结构再用 --data-only 导数据避免把生产环境的统计信息、注释、权限之类的东西一并带过去。按条件导出也是实操里常见的需求比如只想导最近三个月的数据做临时分析pg_dump -U postgres -d mydb -t public.orders --schema-only -f orders_schema.sql真正按行数据过滤需要在 -t 基础上加 --wherepg_dump -U postgres -d mydb -t public.orders --wherecreated_at 2025-01-01 -F c -f orders_part.dump这里想提醒一句--where 是拼进 WHERE 子句的务必注意 SQL 注入和转义问题。虽然大多数场景是自己内部脚本用但养成参数化习惯没坏处。2.2 压缩与并行导出的参数细节pg_dump 的 -Z 参数控制压缩级别范围 0 到 9。默认是压缩的custom 格式会自动压缩。日常我一般不打 -Z让工具走默认级别因为磁盘成本早就没那么敏感了压缩反而拖长导出时间。但在磁盘紧张、或者要跨越公网传输文件的场景把 -Z 调到 5 或 6 是平衡体积和时间的常见选择。再高就没必要了压缩收益递减CPU 开销却涨得很明显。并行导出是靠 -j 参数但有个约束特别容易踩并行模式只支持 directory 格式-Fdcustom 格式不支持并行导出。原因是 custom 是一个单文件流没法多线程写盘。想要并行导出命令要长这样pg_dump -U postgres -d mydb -F d -j 4 -f /backup/mydb_dir-j 4 表示同时用 4 个线程分别导不同的表。要提醒的是并行会显著增加数据库服务端的压力如果你的库本身就在扛核心业务先把 -j 设为 2 或 3 观察一下再往上加。我知道有人图快直接 -j 8结果把生产库 CPU 打满吓得赶紧停掉。这种“优化”得不偿失。目录格式导出来的是一个文件夹里面每个表一个独立文件还有 toc.dat 和 restore.sql 两个辅助文件。后续要处理它直接把这个目录当备份包对待就行压缩它可以用 tar 打包但恢复时最好还是保留目录结构让 pg_restore 直接读目录。2.3 导出过程中的权限与依赖坑导出遇到权限问题时错误信息一般非常直白比如“permission denied for table xxx”。pg_dump 默认会把对象的属主、权限一起导出但导出动作本身需要读取所有对象内容的权限所以至少得是库 owner 或者具备足够权限的角色。实操中我一般用超级用户来做备份省心但如果是给开发环境导数据开发账号权限不够常见做法是让 DBA 用超级用户导出再配合恢复时的 --no-owner 参数在目标库用合适账号接管对象。还有依赖问题。PostgreSQL 对象之间存在引用关系比如函数依赖某个扩展视图依赖某张表。pg_dump 做的是逻辑导出它会根据依赖顺序写入对象定义但如果你用了 --schema-only 然后手动删改脚本破坏了依赖顺序恢复时就会报各种 “relation does not exist” 或 “type does not exist”。遇到这种情况我的建议是别手动整理脚本让工具自己排序顶多是把导出拆成 before.sql 和 after.sql 两段这样可控性更高。另一个常见处理是忽略扩展对象的导出责任比如 postgis、pg_stat_statements 这类扩展到目标库用 CREATE EXTENSION 先装上再用 --extension* 相关参数让 pg_dump 跳过扩展内部的函数否则恢复时会因为目标库已有同名对象而报错。3. 数据导入pg_restore 和 psql 两条主线的完整走法3.1 pg_restore 恢复自定义格式备份pg_restore 命令看起来不算复杂但里面有几个参数会影响恢复成败要单独拎出来讲。pg_restore -h 127.0.0.1 -U postgres -d targetdb /backup/mydb.dump注意pg_restore 不会自动创建数据库本身目标库得先存在。你可以先用 createdb targetdb 建库再执行 pg_restore。如果是空白测试库这个顺序无所谓如果目标库已经有一些对象恢复时会碰到“已存在”的报错。此时加 --clean 会在重建前先 DROP 掉同名对象再加 --if-exists 避免删除不存在的对象时报错pg_restore -h 127.0.0.1 -U postgres -d targetdb --clean --if-exists /backup/mydb.dump这个组合是我在重复恢复同一个备份到同一目标库时的固定搭配不然第二次恢复就一脸报错。但小心--clean 属于“先删后建”一旦中途断了目标库可能处于半空状态所以要么配成脚本里的幂等操作要么确认网络和磁盘稳定后再上。并行恢复用 -j 能大幅缩短时间但注意pg_restore 的并行模式只支持 directory 格式custom 格式传 -j 会直接报错。所以如果你提前知道备份以后可能要做并行恢复导出时就该选 -Fd。目录格式的并行恢复命令如下pg_restore -U postgres -d targetdb -j 4 /backup/mydb_dir对象之间的依赖顺序由 pg_restore 自己保证不用操心。恢复对象不一致时可以只用 --table 或 -t 指定恢复某张表这在紧急恢复“只要某张业务表”时极其好用。有一次客户说订单表数据错了我把备份里那张表单独恢复给开发环境两分钟搞定完全不用全库恢复。3.2 psql 导入 SQL 脚本如果拿到的是 plain 格式 SQL 脚本导入工具就是 psqlpsql -h 127.0.0.1 -U postgres -d targetdb -f /backup/mydb.sqlpsql 执行脚本是逐条发送 SQL 命令任何一步报错默认都不会中止会继续往下跑最后你可能看到一堆 ERROR但数据照样进去了一部分。这在开发环境无所谓生产环境可就麻烦了你以为导成功了实际少了表。所以我强烈建议在明确要求“要么全部成功要么全部失败”的场景下加上psql -h 127.0.0.1 -U postgres -d targetdb -v ON_ERROR_STOP1 -f /backup/mydb.sql加上 -v ON_ERROR_STOP1 后遇到第一个错误立即退出方便你第一时间定位问题。如果脚本里有 BEGIN/ROLLBACK 包装还能配合事务回滚恢复不产生半截数据。导入前还有两个小动作我每次都会做一是把目标库现有的数据先备份一份哪怕恢复失败也能回退二是如果导入的是生产库尽量挑业务低峰期。SQL 脚本导入是全表扫、全量更新锁竞争不会跟你讲情面。3.3 COPY 与 \copy表级数据迁移的利器COPY 是 PostgreSQL 提供的高性能数据搬移命令语法上分服务端 COPY 和客户端 \copy 两种。服务端 COPY 是 SQL 命令由数据库进程直接读写服务器上的文件速度最快但要求文件在数据库服务器本地执行账号也要有对应权限。客户端 \copy 是 psql 的元命令它会把数据从客户端机器传到服务端执行 COPY FROM STDIN文件放在本地不需要超级用户权限用起来最顺手。导出一张表到 CSV常见两种# 客户端方式文件在本地 psql -U postgres -d mydb -c \copy public.users to /tmp/users.csv delimiter , csv header # 服务端方式文件在数据库服务器 psql -U postgres -d mydb -c copy public.users to /tmp/users.csv delimiter , csv header导入时反方向psql -U postgres -d mydb -c \copy public.users from /tmp/users.csv delimiter , csv headerCOPY 比 INSERT 快得多的原因核心在于它把整批数据当成一条大语句减少了每条记录逐条解析、逐条写日志的开销。但如果你用 \copy 从远程导入几百万行中间要经过客户端到服务端的网络传输性能还是会打折。实在大就先上传 CSV 到服务器本地再用服务端 COPY 读取速度天差地别。我测过一次同样 500 万行的表本地 COPY 基本秒级到分钟级\copy 走远程会多出网络和客户端解析时间差距可能拉到十倍。导入前清表和重置序列也是常见动作。清表用 TRUNCATE 而不是 DELETETRUNCATE 不做行级触发、不大量写 WAL速度快得多。导入后别忘了重置序列否则自增主键下次插入会撞唯一约束。可以执行SELECT setval(table_id_seq, max(id)) FROM table;给每个序列补位。4. 跨环境迁移与版本升级两套环境之间的数据互倒4.1 版本差异带来的兼容性判断跨环境迁移最典型的两个场景一是从测试/预发环境同步到生产二是低版本库升级到高版本比如很多线上还在用 PostgreSQL 12、13想升到 16 甚至 17。其实不管你是刚在一个 CentOS 7.9 的服务器上装完新版 PostgreSQL还是用 docker run 拉了一个 postgres:16 容器只要接下来要做的是把旧环境的业务数据灌进去这套 dump/restore 流程就是必经之路。逻辑备份导出导入是跨版本升级里最稳、最不挑环境的方案因为它是文本或通用格式不依赖底层磁盘结构。但版本兼容性有一件事必须想明白用哪个版本的 pg_dump 去导出。经验法则是尽量使用目标端新版 PostgreSQL 自带的 pg_dump 来导源库生成的备份在新版恢复基本不会有问题反过来如果你拿老版本的 pg_dump 去导高版本库很可能因为不认识新对象类型而直接报错或者丢东西。具体操作上我会在目标服务器上装好新版本 PostgreSQL然后用新版本的 pg_dump 通过 TCP 连到源库执行导出# 在目标服务器新版本环境执行 pg_dump -h 旧库地址 -p 5432 -U postgres -d olddb -F c -f /backup/olddb.dump这样做的好处是导出工具版本和目标库版本对齐后面恢复不会在格式兼容上翻车。当然前提是网络打通、防火墙放行 5432。如果你追求更快的原地升级路径可以考虑 pg_upgrade它直接升级数据文件通常比 dump/restore 快几个量级。但它对版本路径、软件安装方式有要求升级前也得做备份。我的态度是核心生产库能走 dump/restore 就别嫌慢它给你的是确定性和随时回退的能力逻辑备份这个过程本身也是验证数据完整性的机会。4.2 属主、表空间、扩展这几个高频处理点跨环境恢复时最经典的报错是role postgres does not exist或者tablespace pg_default does not exist。前者是因为备份里带上了对象属主信息目标环境里没有对应角色。处理方式是在恢复时加 --no-ownerpg_restore -U postgres -d targetdb --no-owner --no-privileges /backup/mydb.dump--no-owner 让恢复后的对象归属到执行恢复命令的用户--no-privileges 则不恢复 GRANT 语句避免权限报错。如果你的目标库需要保留原权限就得先在目标环境创建对应的角色和权限再用默认方式恢复。还有更讲究的做法是用 --role 指定 API 角色让 pg_restore 以指定角色执行恢复从而让对象属主正确落在对应账号上。表空间报错一般出现在源库把对象放在非默认表空间的情况。恢复机没有对应表空间就会报错。解决方案是先建同名表空间或者干脆加 --no-tablespaces 让对象全部落到目标库默认表空间。我常用后者省事。扩展相关的问题也很多。源库装了 postgis、pgcrypto、uuid-ossp恢复脚本里会有 CREATE EXTENSION 语句目标环境可能没装对应扩展包。所以我在恢复之前会先用SELECT name FROM pg_available_extensions;确认目标库有哪些扩展可用缺的话先装系统包或者在恢复时排除扩展对象之后手动 CREATE EXTENSION。扩展版本不一致也会报错比如源库是 postgis 3.3目标库只装了 3.2恢复就会卡在版本检查上。4.3 编码和字符集问题汇总字符集问题说大不大说小不小真碰上乱码能让人挠头很久。PostgreSQL 内部按数据库编码存储常见的库编码有 UTF8、SQL_ASCII、LATIN1。导出的 SQL 脚本里会带SET client_encoding UTF8;这类语句理论上导入时客户端编码能自动对齐但实际上因为各环境 locale 和编码设置不同还是会出现乱码。最普遍的规律是源库和目标库编码一致基本不会出问题编码不一致时提前设置 PGCLIENTENCODING 环境变量可以强制客户端编码。export PGCLIENTENCODINGUTF8 pg_dump -h 源库 -U postgres -d mydb -F c -f mydb.dump如果发现导入后中文变成问号或乱码优先检查两个地方一是目标库的 encoding 是否 UTF8这一步通过SHOW server_encoding;就能确认二是客户端/终端会话的编码是否匹配。实在不行可以用 iconv 先把导出的 SQL 脚本转码再导入比如iconv -f LATIN1 -t UTF8 oldbackup.sql -o newbackup.sql。这个方法虽土但在没别的办法时非常好使。还有一点容易被忽略备份文件本身不是文本时用什么工具 cat 或者 less 查看都会变成乱码。custom 格式是压缩二进制不能直接肉眼查看想看内容得用 pg_restore -l 打印目录列表pg_restore -l /backup/mydb.dump这会把所有包含的对象清单列出来检查备份内容是否完整的首选方式。5. Docker 环境下的 PostgreSQL 导入导出实践5.1 容器内执行 pg_dump 的正确姿势现在很多环境直接用 Docker 跑 PostgreSQL尤其是 Linux 服务器上一条 docker run 就把服务拉起来了导入导出也跟着搬到了容器里。刚开始接触容器 PostgreSQL 的人经常在“容器里没有 pg_dump”“文件怎么拷进容器”这些点上卡住。其实官方 postgres 镜像一般都带全套客户端工具你只是没进对地方。进入容器执行命令的方式是 docker execdocker exec -it pg_container pg_dump -U postgres -F c -f /tmp/mydb.dump mydb这里有个细节-t 参数是给 docker exec 分配伪终端但如果你是在脚本里执行千万别加 -t因为它会分配 TTY 导致输出混入控制字符。直接写docker exec pg_container pg_dump -U postgres -F c -f /tmp/mydb.dump mydb如果容器里没装 pg_dump比如用了精简镜像可以让容器的 PostgreSQL 通过内置 COPY 配合宿主机 psql 走网络导出前提是宿主机装了对应版本的 psql 客户端。从宿主机导容器库的命令和导普通远程库没区别psql -h 127.0.0.1 -p 54321 -U postgres -d mydb -c copy public.users to stdout with csv header /backup/users.csv端口 54321 是你把容器端口映射到宿主机的端口具体数值看你的 docker run 参数。5.2 宿主机与容器之间的数据文件传输容器里导出的备份文件默认留在容器文件系统里重启容器可能会丢必须拷到宿主机保存。docker cp 是从容器向宿主机拷贝的标准动作docker cp pg_container:/tmp/mydb.dump /backup/mydb.dump反过来要把宿主机上的备份文件送进容器再执行恢复docker cp /backup/mydb.dump pg_container:/tmp/mydb.dump docker exec pg_container pg_restore -U postgres -d mydb /tmp/mydb.dump更推荐的做法是在启动容器时就挂载一个数据卷比如运行容器时加参数-v /backup:/backup这样容器内 /backup 目录就是宿主机 /backup 的映射pg_dump 直接写成 /backup/mydb.dump文件天然就在宿主机上省掉 docker cp 步骤也避免了容器被删导致备份丢失的隐患。我的生产容器基本都挂一个备份卷这是底线操作。5.3 一条命令完成容器内的数据导入很多场景下你拿到的备份是一个 SQL 脚本要用 psql 导入容器里的 PostgreSQL。常见做法是把脚本挂载进容器然后执行docker exec -i pg_container psql -U postgres -d mydb -f /backup/mydb.sql如果嫌挂载步骤麻烦可以走 stdin 重定向用管道直接把 SQL 内容喂给容器内 psqldocker exec -i pg_container psql -U postgres -d mydb /backup/mydb.sql注意这里 -i 不是交互式 TTY而是保持 stdin 开启作用就是让 psql 能读到从宿主机重定向进来的内容。我把这条命令当成容器环境下的固定套路比先在容器里 copy 文件、再 exec 执行少一步而且不会在容器文件系统里留临时文件。Docker 场景还有一类特殊操作把容器里的数据库整库导出到宿主机文件。除了 docker exec docker cp也可以直接靠重定向docker exec pg_container pg_dump -U postgres -F c mydb /backup/mydb.dump这样备份文件直接落宿主机不经过容器内文件系统。但为了确保不丢还是建议常备挂载卷方案重定向适合临时应急。6. 大数据量导入的性能调优从慢到快的实用策略6.1 为什么 COPY 比 INSERT 快写入路径拆解很多人对“COPY 就是快”没有概念直到自己导几百万行数据发现 INSERT 慢到怀疑人生。要理解 COPY 快在哪得看 INSERT 单条走的路每执行一条 INSERT数据库都要解析 SQL、检查权限、构造元组、写 WAL 日志、更新索引、维护统计信息。你写个循环一条条插这些开销一次都没省。而 COPY 把成千上万行数据合成一条批量操作解析只做一次元组构造是连续的WAL 记录也可以批量写整体开销被摊薄到极小。同样为什么导大数据前先删索引能快很多因为在每行插入的同时更新 B-tree 索引损耗是可观的。索引在每次都要做树的分裂、页面写入索引不在数据就是顺序追加全部导完再一次性建索引排序和构建的总体开销远小于边插边维护。这个“先删索引、导入、再建索引”的套路对真正的大表导入几乎是必修课。外键和触发器同理。导入时如果目标表有大量外键约束每行都会去做父表检查数据量一大就走不动了。实操中对纯初始化环境的导入我会先禁掉触发器、延迟外键约束对生产环境的增量导入我不敢这么粗暴但可以通过设置session_replication_role replica临时屏蔽触发器需要超级用户权限导入后立即恢复。6.2 导入前的参数开关组合导入大数据前有一组 PostgreSQL 参数可以临时调整让写入路径更顺畅。这些不是常态配置而是“导入任务期间临时打开、导入完成后恢复原样”的开关。maintenance_work_mem控制建索引、VACUUM 等维护操作的内存默认 64MB 太小。导入重建索引时我会临时调高到 1GB 甚至 4GB看机器内存定。max_wal_size 与 checkpoint_timeout调大 max_wal_size 可以降低导入期间 checkpoint 触发频率减少频繁刷盘带来的停顿。比如默认 1GB导入大库时可以调到 8GB 或 16GB然后再调回默认。synchronous_commit设为 off 可以在每次提交时不强制等 WAL 刷盘写入吞吐提升明显但崩溃时可能丢最近未刷盘的提交。测试或可接受丢失的环境可以用生产环境导入时我会先评估因素能不用就不用。fsync这个参数最激进设为 off 后数据库不强制把数据刷到物理磁盘导入速度能翻倍但机器一旦断电数据可能损坏。我的原则是虚拟机搭测试库、临时环境可以用物理机上的数据库尤其有核心业务在里面坚决不动宁可多等一会儿。full_page_writes设为 off 可以避免每次 checkpoint 后首个页面写入带全页镜像写入量减少导入更快。但同样有风险涉及崩溃恢复一致性必须和 fsync off 一样谨慎导入完立即恢复。组合写成的配置大致是这样ALTER SYSTEM SET maintenance_work_mem 1GB; ALTER SYSTEM SET max_wal_size 16GB; ALTER SYSTEM SET checkpoint_timeout 15min; SELECT pg_reload_conf();导入完成后记得改回去否则这个“导入专用配置”会留在生产库上带来内存占用偏高、WAL 增长量大等新隐患。6.3 常见导入瓶颈排查与实测结论导入慢未必是参数没调好也可能是根本没走到预期路径。我排导入瓶颈的顺序一般是先看目标机 CPU 和磁盘 IO再看等待事件再用工具确认是不是在跑 COPY。如果你的 PostgreSQL 版本在 14 以上可以直接查 pg_stat_progress_copy 视图观察 COPY 的进度这比盲等强太多SELECT datname, relname, bytes_processed, bytes_total, tuples_processed FROM pg_stat_progress_copy;还有一点常被忽略导入端的数据库日志和磁盘空间。WAL 增长是大数据导入最容易被忽视的杀手。如果 max_wal_size 不够导入过程中会频繁 checkpoint磁盘被 WAL 文件占满业务直接故障。先 df -h 看一眼剩余空间再开始导不寒碜。最后说一次我自己的实测数据给大家一个参考量级。一个约 5GB 的订单库最初用逐条 INSERT 导入花了 40 多分钟改成 COPY 后调到 10 分钟级别再配合“先删索引、导入后重建”和 maintenance_work_mem 调整总时间压到 3 分钟左右。同一个备份文件恢复方式不同时间差十倍的例子我见过不止一次。数据量越大前期的准备工作越值钱。多数时候慢不是数据库不给力而是没给够合适的执行条件。这些年干下来我的体会是PostgreSQL 导入导出这套东西真的值得专门花时间系统捋一遍。版本升级、环境迁移、日常备份、故障恢复哪一样都绕不开它。你在命令前多琢磨一下格式选型在参数调整上多留一份敬畏就能少踩很多坑也少加很多班。以后从生产环境抽数也好给新项目灌初始数据也好这套能力会让你处理得比大多数人快上一截。
返回列表