【GaussDB】507版本gs_dump功能更新
前言
GaussDB 507内核版本的gs_dump有了不少更新,而且客户在之前版本的实际使用过程中,的确发现了不少毛病,但版本说明书上并未列全所有新增和修改,这次就来借助AI看一下到底动了些啥,并且对之前版本的一些问题进行测试
比较这两个文档的差异
https://doc.hcs.huawei.com/db/zh-cn/gaussdbqlh/26.861.0/rf-cent/gaussdb-38-0940.html
https://doc.hcs.huawei.com/db/zh-cn/gaussdbqlh/25.1.32/tg-cent/gaussdb-38-0012.html
GaussDB gs_dump 文档差异对比
两个文档均为 "gs_dump导出数据库信息" 页面,分别来自不同版本:
| 属性 | 旧版 (25.1.32) | 新版 (26.861.0) |
|---|---|---|
| 文档版本 | 25.1.32 | 26.861.0 |
| 内核版本 | 505.2.1.SPC0800 | 507.0.0 |
| URL路径 | /tg-cent/gaussdb-38-0012.html | /rf-cent/gaussdb-38-0940.html |
| 文档分类 | 工具参考(集中式) | 参考(集中式) |
| 内容长度 | ~20,234 字符 | ~24,244 字符 |
| 版权年份 | 2024 | 2024 |
一、工具介绍部分
| 差异项 | 旧版 (25.1.32) | 新版 (26.861.0) |
|---|---|---|
| 默认数据库描述 | "支持导出的数据库可以是默认数据库postgres" | "支持导出的数据库可以是默认数据库"(去掉了具体名称) |
| 归档格式导入工具说明 | "使用gs_restore可以选择要从自定义归档/目录归档/tar归档导出文件中导入相应的数据库对象" | "这三种归档格式,必须使用5.7.5-gs_restore进行对象和数据的导入。gs_restore也可以选择要导入的数据库对象" |
二、注意事项部分(变化最大)
新增的注意事项(旧版没有,新版新增)
- CREATE EVENT定时任务检查:通过CREATE EVENT语法创建的定时任务若无法被导出,请检查gs_job_attribute表中定时任务job_style属性是否为EVENT
- 触发器导出要求:当导出对象中包含触发器时,需要加上参数
--use-set-session-authorization --all,并通过文本模式导出 - model对象:使用gs_dump不会转储model对象
- 系统管理员导出限制:系统管理员导出时不会导出初始用户创建的对象,需使用初始用户进行导出
- 依赖PACKAGE内部函数的视图:首次导入目标端时会报错,需使用
gs_dump --schema-only备份元数据再次导入 - 高级压缩库级策略定义:需全库导出且系统管理员权限,否则策略以表/分区级独立策略形式导出
- 间隔分区表:只能导出range分区部分,不能导出interval分区部分
- ddl_invalid_mode=invalid的影响:函数和包drop操作时不级联删除,导出时会因依赖关系找不到对象而报错
- 失效视图:默认导出失效视图,可指定
--ignore-invalid-views不导出 - rowid系统列:不导出rowid系统列上的数据,仅导出rowid作为数据类型时用户列的数据
- M-Compatibility零字符截断:含零字符('\0')数据进行gs_dump操作时存在数据截断
删除的注意事项(旧版有,新版去掉)
gs_dump时生成列不会被转储(已删除)初始用户创建的表上含用户自定义函数的表达式索引,系统管理员导出后需用初始用户导入(已删除)
修改的注意事项
| 项目 | 旧版 | 新版 |
|---|---|---|
| IMCV元信息位置 | 在注意事项中间 | 移至注意事项开头,措辞微调 |
| 锁描述 | "gs_dump会对需要转储的表设置共享锁" | "gs_dump默认会对需要转储的表设置ACCESS SHARE级别锁",新增"锁与锁之间的冲突请参见LOCK" |
| 不导出的表 | "以matviewmap_和mlog_前缀开头的表" | 新增"带有internal_mask选项的表、回收站中的表" |
| 普通用户导出权限 | "仅会导出owner归属于该普通用户的对象" | "仅会导出owner归属于该普通用户的所有对象" |
| 对象数量过多措辞 | "不适合使用在" | "不适合应用于" |
三、参数说明部分
新增参数(旧版没有)
| 参数 | 说明 |
|---|---|
--ignore-invalid-views | 不导出失效视图,导出时发现有失效视图会打印提示 |
-j, --jobs=NUM | 并行导出,指定并行数,不支持超过客户端CPU核数两倍。仅支持目录归档格式,与--inserts/--query等冲突。支持表内并行导出 |
--disable-inter-table-parallel | 关闭表内并行,使用表级别并行导出 |
--include-query-file=FILENAME | 通过文件批量配置谓词过滤条件,支持[schema_name.][table_name:] query_clause格式 |
--query=[schema_name.][table_name:]query_clause | 谓词过滤导出数据,支持多表多条件,包含详细的使用示例和转义规则 |
--with-copy-format=FILE_FORMAT | 指定导出数据文件格式(TEXT/CSV),默认TEXT,CSV仅支持目录归档模式 |
--no-transaction | DDL语句不再被额外包裹在BEGIN/COMMIT中 |
--log-level=LOG|DEBUG|DEBUG1|DEBUG2|DEBUG3 | 指定gs_dump日志级别 |
修改的参数
| 参数 | 旧版 | 新版 |
|---|---|---|
-a, --data-only | "转储表数据、大对象和序列值" | "转储表数据和序列值"(去掉大对象) |
-c, --clean | 仅简单描述 | 新增非级联删除DROP命令说明和具体报错示例 |
-C, --create | 描述分两段 | 合并为一段;"创出"改为"创建出" |
-E, --encoding | "也可以得到相同的结果" 改为 "与该选项功能相同" | 措辞调整;转码场景描述微调 |
-o, --oids | 无限制说明 | 新增"不能与--inserts/--column-inserts选项一起使用" |
-t, --table | 示例在参数说明末尾 | 示例移至参数定义后;新增多分隔符说明(倒数两个分隔符生效) |
-Z, --compress | 无取值规则说明 | 新增"系统将取遇到的第一个非数字字符之前的部分" |
--lock-wait-timeout | "在转储开始时不一直等待获取共享表锁" | "请勿在转储刚开始时一直等待以获取共享表锁",新增"参数单位为ms(毫秒)" |
--non-lock-table | "对表的加锁行为"、"要导出的TABLE" | "对表加锁的行为"、"要导出的table"(大小写调整) |
--use-set-session-authorization | 描述无空行分隔 | 新增空行分隔,"以上使用范围的限制" |
-?, --help | "显示gs_dump命令行参数帮助信息" | "显示gs_dump命令行参数帮助,然后退出" |
--binary-upgrade | 仅"扩展预留接口" | 新增"M-Compatibility模式数据库不支持该选项" |
--exclude-with | "末尾不添加WITH(...)这样的描述" | "末尾不添加WITH(...)等描述" |
--extension | "不建议用户使用" | "只允许操作数据库内部的高级包或扩展" |
删除的参数说明
M-Compatibility兼容模式下(已删除)-n参数受lower_case_table_names影响的说明M-Compatibility兼容模式下(已删除)-t参数受lower_case_table_names影响的说明
新增的连接参数说明
- 普通用户权限导出/导入时,需在导入前赋权:
GRANT CREATE ON DATABASE db_xxx TO user_xxx
四、其他变化
| 项目 | 旧版 | 新版 |
|---|---|---|
| DBNAME使用方式 | 无 | 新增"DBNAME详细使用方式参见gsql使用指导中表6" |
| 相关工具 | "gs_dumpall导出所有数据库信息,gs_restore导入数据" | 新增"gsql连接数据库" |
| M-Compatibility兼容模式措辞 | "M-Compatibility兼容模式下" | "M-Compatibility模式数据库下"(多处统一修改) |
五、总结
新版 (26.861.0) 相比旧版 (25.1.32) 主要有以下方向的增强:
- 并行导出能力:新增
-j/--jobs、--disable-inter-table-parallel等并行导出参数,支持表内并行和表级别并行 - 谓词过滤导出:新增
--query和--include-query-file参数,支持按条件导出部分表数据 - 数据文件格式:新增
--with-copy-format支持 CSV 格式导出 - 失效视图处理:新增
--ignore-invalid-views参数 - 事务控制:新增
--no-transaction参数 - 日志级别:新增
--log-level参数 - 注意事项大幅扩充:新增间隔分区表、触发器导出、高级压缩策略、rowid系统列等十余条注意事项
- 锁机制描述更精确:从"共享锁"改为"ACCESS SHARE级别锁",并补充锁冲突参考
分析文档差异
从文档里的修改点来看,算是非常扣细节了,个人猜测要么是请了个有强迫症(褒义)的文档专家,要么就是用了AI。
除了官方产品文档上体现的差异,还有一个点仅体现在版本说明书里
3.版本号、兼容性等重复查询SQL归一化复用优化;对函数、视图、表等容易出现超多对象的类型在dump过程中的sql进行分析合并,减少SQL执行次数。
这个点其实很重要,因为实践中经常会遇到,要导出指定的一个表,gs_dump元数据查询处理用了10分钟,然后实际对于这个表的导出本身,只用了1秒。这是PG系一直饱受诟病的依赖对象解环排序处理所导致的。即就算指定了要导出的对象,也仍然会扫描库中所有的对象,识别依赖关系去进行排序。当对象多、依赖关系复杂时,这个处理过程就会非常慢。不过我暂不确定GaussDB 507版本的这个优化效果到底怎样,但至少华为是有行动了。
综合以上内容,个人判断,对于一个正常的用户环境,历史上用户最关心的两个问题--
gs_dump的导出性能和导出范围控制,在GaussDB 507 版本上都得到了加强。其中最为重要的为以下三个能力
- 并行导出(性能)
- 元数据查询SQL合并(性能)
- 谓词过滤导出(导出范围控制)
- 不导出无效视图(导出范围控制)
大概设计几个测试场景
-
并行导出(建新库)
- 一张表十个字段百万行 并行 1到4
- 两张表十个字段百万行 并行 1到4
-
元数据查询SQL合并(建新库)
- 十万张空表
- 一万个自定义类型,一百个package,每个package里一百个function,均引用不同自定义类型,一百个视图,每个视图引用一百个package里的函数
-
谓词过滤导出(建新库)
- 三张表,两个基于日期,一个不带日期
-
不导出无效视图(建新库)
- 打开视图依赖开关,创建表,创建视图,删除表 ,观察导出全库,看是否报错,再配置上不导出无效视图,看效果
我让AI读了本文以上部分,生成了测试shell脚本,内容太多且有多个文件,我就不发出来了,不过我另外让AI再生成了一份手动测试命令的文档,以供参考:
GaussDB 507 gs_dump 手动测试命令清单
从 01~04 测试脚本中提取所有 gsql / gs_dump 执行命令,按场景顺序排列,可直接复制运行。
导出文件默认放当前目录,如需统一存放可自行加路径前缀。0. 连接方式说明
脚本中 gsql / gs_dump 均采用默认连接(依赖
PGHOST/PGPORT/PGUSER环境变量或~/.pgpass)。如需显式指定:# 默认(推荐,配好 .pgpass 后最简洁) gsql -d test_parallel -c "SELECT 1;" # 显式指定连接参数 gsql -h 127.0.0.1 -p 5432 -U gaussdb -W '密码' -d test_parallel -c "SELECT 1;" gs_dump -h 127.0.0.1 -p 5432 -U gaussdb -W '密码' test_parallel -F d ...下文命令均按默认连接写法。耗时手动测可在命令前加
time。
场景1:并行导出(-j / --jobs)
1.0 建库
gsql -d postgres -c "DROP DATABASE IF EXISTS test_parallel;" gsql -d postgres -c "CREATE DATABASE test_parallel;"1.1 建表 + 生成数据(2 表 × 100 万行)
gsql -d test_parallel -c " DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1 ( id bigint , c1 bigint, c2 bigint, c3 numeric(18,2), c4 text, c5 varchar(64), c6 varchar(64), c7 timestamp, c8 boolean, c9 integer ); INSERT INTO t1 (id,c1,c2,c3,c4,c5,c6,c7,c8,c9) SELECT g,g, g*2, g*1.23, 'text_'||g, 'vc_'||(g%1000), 'name_'||(g%500), now() - (g || ' seconds')::interval, (g%2=0), g%9999 FROM generate_series(1, 10000000) g; CREATE TABLE t2 as SELECT * FROM t1; "1.2 校验行数
gsql -d test_parallel -t -A -c "SELECT count(*),pg_table_size('t1') FROM t1;" gsql -d test_parallel -t -A -c "SELECT count(*),pg_table_size('t2') FROM t2;"1.3 单表 t1 并行导出(jobs 1→4,目录归档 -F d)
rm -rf out_t1_j1 && time gs_dump test_parallel -F d -j 1 -t public.t1 -f out_t1_j1 rm -rf out_t1_j2 && time gs_dump test_parallel -F d -j 2 -t public.t1 -f out_t1_j2 rm -rf out_t1_j3 && time gs_dump test_parallel -F d -j 3 -t public.t1 -f out_t1_j3 rm -rf out_t1_j4 && time gs_dump test_parallel -F d -j 4 -t public.t1 -f out_t1_j4注意:gs_dump
-F d要求-f目录不存在,由 gs_dump 自行创建,故先rm -rf。1.4 双表 t1+t2 并行导出(默认表内并行)
rm -rf out_t1t2_j1 && time gs_dump test_parallel -F d -j 1 -t public.t1 -t public.t2 -f out_t1t2_j1 rm -rf out_t1t2_j2 && time gs_dump test_parallel -F d -j 2 -t public.t1 -t public.t2 -f out_t1t2_j2 rm -rf out_t1t2_j3 && time gs_dump test_parallel -F d -j 3 -t public.t1 -t public.t2 -f out_t1t2_j3 rm -rf out_t1t2_j4 && time gs_dump test_parallel -F d -j 4 -t public.t1 -t public.t2 -f out_t1t2_j41.5 双表 t1+t2 表级别并行(--disable-inter-table-parallel)
rm -rf out_t1t2_tbl_j1 && time gs_dump test_parallel -F d -j 1 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tbl_j1 rm -rf out_t1t2_tbl_j2 && time gs_dump test_parallel -F d -j 2 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tbl_j2 rm -rf out_t1t2_tbl_j3 && time gs_dump test_parallel -F d -j 3 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tbl_j3 rm -rf out_t1t2_tbl_j4 && time gs_dump test_parallel -F d -j 4 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tbl_j4
场景2:元数据查询SQL合并
2.0 建库(空表环境)
gsql -d postgres -c "DROP DATABASE IF EXISTS test_meta_merge;" gsql -d postgres -c "CREATE DATABASE test_meta_merge;"2.1 生成 N 张空表
完整规模(10 万张,耗时很长):
awk 'BEGIN{for(i=1;i<=100000;i++) printf("CREATE TABLE empty_t_%d (id int);\n", i)}' > gen_empty_tables.sql gsql -d test_meta_merge -f gen_empty_tables.sql小规模验证(1 万张,先跑通流程):
awk 'BEGIN{for(i=1;i<=10000;i++) printf("CREATE TABLE empty_t_%d (id int);\n", i)}' > gen_empty_tables.sql gsql -d test_meta_merge -f gen_empty_tables.sql2.2 空表库全库 schema-only 导出
rm -f meta_empty_all.dmp && time gs_dump test_meta_merge -F c -s -f meta_empty_all.dmp2.3 空表库单表 schema-only 导出(验证指定单对象是否仍扫描全库依赖)
rm -f meta_empty_one.dmp && time gs_dump test_meta_merge -F c -s -t public.empty_t_1 -f meta_empty_one.dmp2.4 建库(复杂依赖环境)
gsql -d postgres -c "DROP DATABASE IF EXISTS test_meta_complex;" gsql -d postgres -c "CREATE DATABASE test_meta_complex;"2.5 生成复杂依赖对象 DDL 文件
完整规模:1 万类型 + 100 包×100 函数 + 100 视图。小规模把 10000 改 1000、100 改 10。
# 1) 1万个自定义类型 awk 'BEGIN{for(i=1;i<=10000;i++) printf("CREATE TYPE typ_%d AS (a int, b varchar(32));\n", i)}' > gen_complex_objects.sql # 2) 100个package,每个100个function,引用不同类型 awk 'BEGIN{ for(pi=1;pi<=100;pi++){ printf("CREATE OR REPLACE PACKAGE pkg_%d IS\n", pi); for(fi=1;fi<=100;fi++) printf(" FUNCTION f_%d RETURN typ_%d;\n", fi, (pi-1)*100+fi); printf("END;\n/\n"); printf("CREATE OR REPLACE PACKAGE BODY pkg_%d IS\n", pi); for(fi=1;fi<=100;fi++) printf(" FUNCTION f_%d RETURN typ_%d IS\n BEGIN RETURN NULL; END;\n", fi, (pi-1)*100+fi); printf("END;\n/\n"); } }' >> gen_complex_objects.sql # 3) 100个视图,每个引用100个package里的function awk 'BEGIN{ for(k=1;k<=100;k++){ printf("CREATE OR REPLACE VIEW v_%d AS SELECT ", k); for(pi=1;pi<=100;pi++){ printf("pkg_%d.f_%d() AS c%d", pi, k, pi); if(pi<100) printf(", "); } printf(" FROM dual;\n"); } }' >> gen_complex_objects.sql2.6 执行复杂对象创建
gsql -d test_meta_complex -f gen_complex_objects.sql2.7 复杂依赖库全库 schema-only 导出
rm -f meta_complex_all.dmp && time gs_dump test_meta_complex -F c -s -f meta_complex_all.dmp
场景3:谓词过滤导出(--query / --include-query-file)
3.0 建库
gsql -d postgres -c "DROP DATABASE IF EXISTS test_query_filter;" gsql -d postgres -c "CREATE DATABASE test_query_filter;"3.1 建表 + 生成数据(3 表 × 10 万行)
gsql -d test_query_filter -c " DROP TABLE IF EXISTS orders1; DROP TABLE IF EXISTS orders2; DROP TABLE IF EXISTS products; CREATE TABLE orders1 (id bigserial PRIMARY KEY, amt numeric(18,2), create_date date); CREATE TABLE orders2 (id bigserial PRIMARY KEY, amt numeric(18,2), create_date date); CREATE TABLE products (id bigserial PRIMARY KEY, name varchar(64), price numeric(18,2)); INSERT INTO orders1 (amt, create_date) SELECT g*1.5, timestamp '2025-01-01' + (g % 365) FROM generate_series(1, 100000) g; INSERT INTO orders2 (amt, create_date) SELECT g*2.5, timestamp '2025-01-01' + (g % 365) FROM generate_series(1, 100000) g; INSERT INTO products (name, price) SELECT 'p_'||g, g*9.9 FROM generate_series(1, 100000) g; "3.2 校验源库行数
gsql -d test_query_filter -t -A -c "SELECT count(*) FROM orders1;" gsql -d test_query_filter -t -A -c "SELECT count(*) FROM orders2;" gsql -d test_query_filter -t -A -c "SELECT count(*) FROM products;"3.3 --query 单表日期过滤导出(orders1 三月数据)
# 预期行数 gsql -d test_query_filter -t -A -c "SELECT count(*) FROM orders1 WHERE create_date >= timestamp '2025-03-01' AND create_date < timestamp '2025-04-01';" # 导出 rm -f query_single.sql gs_dump test_query_filter -F p -a -t public.orders1 \ --query="orders1:WHERE create_date >= timestamp '2025-03-01' AND create_date < timestamp '2025-04-01'" \ -f query_single.sql # 校验导出行数(COPY块数据行) awk '/^COPY[ \t].*orders1[ \t(]/{f=1;next} f&&/^\\\.$/{f=0} f{c++} END{print c+0}' query_single.sql3.4 --include-query-file 多表批量过滤(orders1/orders2 六月数据)
# 谓词配置文件 cat > query_filter.conf <<'EOF' orders1:WHERE create_date >= timestamp '2025-06-01' AND create_date < timestamp '2025-07-01' orders2:WHERE create_date >= timestamp '2025-06-01' AND create_date < timestamp '2025-07-01' EOF # 预期行数 gsql -d test_query_filter -t -A -c "SELECT count(*) FROM orders1 WHERE create_date >= timestamp '2025-06-01' AND create_date < timestamp '2025-07-01';" gsql -d test_query_filter -t -A -c "SELECT count(*) FROM orders2 WHERE create_date >= timestamp '2025-06-01' AND create_date < timestamp '2025-07-01';" # 导出 rm -f query_multi.sql gs_dump test_query_filter -F p -a -t public.orders1 -t public.orders2 \ --include-query-file=query_filter.conf -f query_multi.sql # 校验导出行数 awk '/^COPY[ \t].*orders1[ \t(]/{f=1;next} f&&/^\\\.$/{f=0} f{c++} END{print c+0}' query_multi.sql awk '/^COPY[ \t].*orders2[ \t(]/{f=1;next} f&&/^\\\.$/{f=0} f{c++} END{print c+0}' query_multi.sql3.5 不带日期表全量导出(products 对照)
rm -f query_products.sql gs_dump test_query_filter -F p -a -t public.products -f query_products.sql # 校验 awk '/^COPY[ \t].*products[ \t(]/{f=1;next} f&&/^\\\.$/{f=0} f{c++} END{print c+0}' query_products.sql
场景4:不导出失效视图(--ignore-invalid-views)
4.0 建库
gsql -d postgres -c "DROP DATABASE IF EXISTS test_invalid_views;" gsql -d postgres -c "CREATE DATABASE test_invalid_views;"4.1 建表 + 建视图 + 查询(删除前)
gsql -d test_invalid_views -c " DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; CREATE TABLE t1 (id int, name varchar(32)); INSERT INTO t1 VALUES (1,'a'),(2,'b'); CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1; " gsql -d test_invalid_views -c "SELECT count(*) FROM v1;"4.2 打开视图依赖开关 + 删除表使视图失效
enable_view_invalidation必须与DROP TABLE在同一 session 才生效(gsql-c每次是新 session),故合并执行:gsql -d test_invalid_views -c " SET enable_view_invalidation = on; DROP TABLE t1; "若
SET报参数不存在或为 SIGHUP/POSTMASTER 级别,改用全局设置后重连:gs_guc reload -D $PGDATA -c "enable_view_invalidation=on" gsql -d test_invalid_views -c "DROP TABLE t1;"4.3 确认视图已失效
gsql -d test_invalid_views -c "SELECT viewname FROM pg_views WHERE viewname='v1';" # 查询 v1 应报错(依赖对象不存在) gsql -d test_invalid_views -c "SELECT * FROM v1;"4.4 全库默认导出(观察是否报错 / 是否导出失效视图)
rm -f inv_default.sql gs_dump test_invalid_views -F p -f inv_default.sql echo "退出码: $?" grep -c "VIEW v1\|view v1" inv_default.sql # 是否含 v1 定义4.5 --ignore-invalid-views 全库导出
rm -f inv_ignore.sql gs_dump test_invalid_views -F p --ignore-invalid-views -f inv_ignore.sql echo "退出码: $?" grep -c "VIEW v1\|view v1" inv_ignore.sql # 应为 0(跳过失效视图) grep -iE "invalid|ignore|skip" inv_ignore.sql # 观察是否有跳过提示
附:清理测试库
gsql -d postgres -c "DROP DATABASE IF EXISTS test_parallel;" gsql -d postgres -c "DROP DATABASE IF EXISTS test_meta_merge;" gsql -d postgres -c "DROP DATABASE IF EXISTS test_meta_complex;" gsql -d postgres -c "DROP DATABASE IF EXISTS test_query_filter;" gsql -d postgres -c "DROP DATABASE IF EXISTS test_invalid_views;"
测试日志
大表并行
百万行十个字段 并行测试
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 1 -f testdir1
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:38]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:39]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:43]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:43]: total time: 5706 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 2 -f testdir2
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:52]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:53]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:56]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:29:56]: total time: 3754 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 3 -f testdir3
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:05]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:06]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:08]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:08]: total time: 3064 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 4 -f testdir4
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:16]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:17]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:18]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:18]: total time: 2700 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 5 -f testdir5
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:24]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:25]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:26]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:26]: total time: 2602 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 6 -f testdir6
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:33]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:34]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:35]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:35]: total time: 2501 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 7 -f testdir7
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:42]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:43]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:45]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:45]: total time: 2847 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 8 -f testdir8
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:52]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:53]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:54]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:30:54]: total time: 2409 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 7 -f testdir7
could not create directory "/home/gaussdb/gs_dump_507_test/testdir7": File exists
[gaussdb@c93206eee3b8 gs_dump_507_test]$ rm -rf testdir7
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_parallel -F d -j 7 -f testdir7
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:31:18]: The total objects number is 493.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:31:19]: [100.00%] 493 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:31:20]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 01:31:20]: total time: 2411 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$
千万行十个字段 并行测试
[gaussdb@c93206eee3b8 ~]$ gsql -d postgres -c "DROP DATABASE IF EXISTS test_parallel;"
DROP DATABASE
[gaussdb@c93206eee3b8 ~]$ gsql -d postgres -c "CREATE DATABASE test_parallel;"
CREATE DATABASE
[gaussdb@c93206eee3b8 ~]$ gsql -d test_parallel -c "
> DROP TABLE IF EXISTS t1;
> DROP TABLE IF EXISTS t2;
> CREATE TABLE t1 (
> id bigint ,
> c1 bigint, c2 bigint, c3 numeric(18,2),
> c4 text, c5 varchar(64), c6 varchar(64),
> c7 timestamp, c8 boolean, c9 integer
> );
> INSERT INTO t1 (id,c1,c2,c3,c4,c5,c6,c7,c8,c9)
> SELECT g,g, g*2, g*1.23, 'text_'||g, 'vc_'||(g%1000), 'name_'||(g%500),
> now() - (g || ' seconds')::interval, (g%2=0), g%9999
> FROM generate_series(1, 10000000) g;
> CREATE TABLE t2 as SELECT * FROM t1;
> "
NOTICE: table "t1" does not exist, skipping
DROP TABLE
NOTICE: table "t2" does not exist, skipping
DROP TABLE
CREATE TABLE
INSERT 0 10000000
INSERT 0 10000000
[gaussdb@c93206eee3b8 ~]$ gsql -d test_parallel -t -A -c "SELECT count(*),pg_table_size('t1') FROM t1;"
10000000|1005723648
[gaussdb@c93206eee3b8 ~]$ gsql -d test_parallel -t -A -c "SELECT count(*),pg_table_size('t2') FROM t2;"
10000000|1005723648
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 1 -t public.t1 -f out_t1_j1
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:28:05]: The total objects number is 480.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:28:06]: [100.00%] 480 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:28:28]: dump table public.t1 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:28:28]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:28:28]: total time: 23696 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 2 -t public.t1 -f out_t1_j2
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:00]: The total objects number is 480.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:01]: [100.00%] 480 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:14]: dump table public.t1 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:14]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:14]: total time: 13760 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 4 -t public.t1 -f out_t1_j4
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:42]: The total objects number is 480.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:42]: [100.00%] 480 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:50]: dump table public.t1 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:50]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:29:50]: total time: 8638 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 8 -t public.t1 -f out_t1_j8
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:30:02]: The total objects number is 480.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:30:03]: [100.00%] 480 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:30:08]: dump table public.t1 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:30:08]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:30:08]: total time: 6334 ms
[gaussdb@c93206eee3b8 ~]$ du -h out* -d 1
260M out_t1_j1
260M out_t1_j2
260M out_t1_j4
260M out_t1_j8
并行效果挺好
双表测试 不关闭表内并行
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 1 -t public.t1 -t public.t2 -f out_t1t2_j1
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:33:44]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:33:45]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:34:29]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:34:29]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:34:29]: total time: 45921 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 2 -t public.t1 -t public.t2 -f out_t1t2_j2
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:34:57]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:34:58]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:22]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:22]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:22]: total time: 25039 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 4 -t public.t1 -t public.t2 -f out_t1t2_j4
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:36]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:37]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:52]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:52]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:35:52]: total time: 16018 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 8 -t public.t1 -t public.t2 -f out_t1t2_j8
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:36:05]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:36:06]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:36:16]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:36:16]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:36:16]: total time: 11802 ms
[gaussdb@c93206eee3b8 ~]$
双表测试 关闭表内并行
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 1 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tbl_j1
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:38:04]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:38:05]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:38:49]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:38:49]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:38:49]: total time: 45657 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 2 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tb
l_j2
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:03]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:04]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:28]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:28]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:28]: total time: 25193 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 4 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tb
l_j4
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:39]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:39:40]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:04]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:04]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:04]: total time: 25486 ms
[gaussdb@c93206eee3b8 ~]$ gs_dump test_parallel -F d -j 8 -t public.t1 -t public.t2 --disable-inter-table-parallel -f out_t1t2_tb
l_j8
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:15]: The total objects number is 482.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:15]: [100.00%] 482 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:40]: dump table public.t1 public.t2 successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:40]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 02:40:40]: total time: 25527 ms
可以看到由于只有两张表,并行度2、4、8的耗时一样。
大量对象
10万张空表导出的测试,等了一个小时没有动静,查看pg_stat_activity,发现gs_dump在查行级权限,而且是一张表一张表的查
test_meta_merge=# explain analyze SELECT rlspolicy.polrelid, rlspolicy.oid, rlspolicy.polname, rlspolicy.polcmd, rlspolicy.polpermissive, CASE WHEN rlspolicy.polroles = '{0}' THEN 'public' ELSE pg_catalog.array_to_string(ARRAY(SELECT pg_roles.rolname FROM pg_catalog.pg_roles WHERE pg_roles.oid = ANY(rlspolicy.polroles) ORDER BY pg_roles.rolname), ', ') END AS polroles, pg_catalog.pg_get_expr(rlspolicy.polqual, rlspolicy.polrelid) AS polqual FROM pg_catalog.pg_rlspolicy rlspolicy WHERE rlspolicy.polrelid = 84062;
id | operation | A-time | A-rows | E-rows | Peak Memory | A-width | E-width |
E-costs
----+-----------------------------------------------------------------------------------------------+--------+--------+--------+-------------+---------+---------+--
-------------
1 | -> Index Scan using pg_rlspolicy_polrelid_polname_index on pg_rlspolicy rlspolicy | 0.015 | 0 | 2 | 99KB | | 138 | 0
.000..19.861
2 | -> Index Scan using pg_authid_rolname_index on pg_authid [1, SubPlan 3] | | | 6 | | | 72 | 4
.541..8.280
3 | -> Index Scan using pg_authid_rolname_index on pg_authid [2, InitPlan 1 (returns $0)] | | | 1 | | | 1 | 0
.003..2.270
4 | -> Index Scan using pg_authid_rolname_index on pg_authid [2, InitPlan 2 (returns $1)] | | | 1 | | | 1 | 0
.003..2.270
(4 rows)
Predicate Information (identified by plan id)
-----------------------------------------------------------------------------------------------------------------------------------
1 --Index Scan using pg_rlspolicy_polrelid_polname_index on pg_rlspolicy rlspolicy
Index Cond: (polrelid = 84062::oid), (Expression Flatten Optimized)
2 --Index Scan using pg_authid_rolname_index on pg_authid
Filter: (((rolname = "current_user"()) OR $0 OR $1) AND (oid = ANY (rlspolicy.polroles))), (Expression Flatten Optimized)
3 --Index Scan using pg_authid_rolname_index on pg_authid
Index Cond: (rolname = "current_user"()), (Expression Flatten Optimized)
4 --Index Scan using pg_authid_rolname_index on pg_authid
Index Cond: (rolname = "current_user"()), (Expression Flatten Optimized)
(8 rows)
====== Query Summary =====
----------------------------------------
Datanode executor start time: 0.113 ms
Datanode executor run time: 0.057 ms
Datanode executor end time: 0.018 ms
Planner runtime: 0.986 ms
Query Id: 6920906727361986907
Total runtime: 0.204 ms
(6 rows)
循环这么查,开销挺大,实测一个小时查了不到两万张表,而十万张表创建也才10分钟。如果一开始就全量查一下,没有配置,后续就不处理rls了;如果有配置,后续也可以直接用查出来的东西,这样性能可能会更好。不过如果表只有1000张,那么导出只要4秒,表越多,性能成指数下降.
openGauss也有这段代码,来自于6年前,从首次开源起就没改过
/* get the row level security policy from pg_rlspolicy(skip policies for system catalog) */
appendPQExpBuffer(query,
"SELECT rlspolicy.polrelid, rlspolicy.oid, rlspolicy.polname, "
"rlspolicy.polcmd, rlspolicy.polpermissive, "
"CASE WHEN rlspolicy.polroles = '{0}' THEN 'public' ELSE "
"pg_catalog.array_to_string(ARRAY(SELECT pg_roles.rolname FROM pg_roles "
"WHERE pg_roles.oid = ANY(rlspolicy.polroles) ORDER BY pg_roles.rolname), ', ') END AS polroles, "
"pg_catalog.pg_get_expr(rlspolicy.polqual, rlspolicy.polrelid) AS polqual "
"FROM pg_catalog.pg_rlspolicy rlspolicy WHERE rlspolicy.polrelid = %u;",
(Oid)tbinfo->dobj.catId.oid);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
偶尔也可以看到有这样的SQL,也是一张表一张表的查,当然还有其他sql也是这样,只是开销最大的应该还是上面那个行级规则
SELECT pr.tableoid, pr.oid, p.pubname FROM pg_catalog.pg_publication_rel pr, pg_catalog.pg_publication p WHERE pr.prrelid = '456779' AND p.oid = pr.prpubid
============================================================
| 场景 | 测试项 | 耗时 | 备注
| ---------------------- | ------------------------------ | ----------- | ----
| 元数据SQL合并-建表 | 1000张空表 | 6.135 s | 数据准备耗时
| 元数据SQL合并 | 空表库全库schema-only | 4.165 s | 对象=1000
| 元数据SQL合并 | 空表库单表schema-only | 1.156 s | 指定1表/库内1000表
| 元数据SQL合并-建对象 | 类型10000+包100x100+视图100 | 253.204 s | 数据准备耗时
| 元数据SQL合并 | 复杂依赖全库schema-only | 118.783 s | 对象=类型+包+函数+视图
| 场景 | 测试项 | 耗时 | 备注
| ---------------------- | ------------------------------ | ----------- | ----
| 元数据SQL合并-建表 | 10000张空表 | 65.163 s | 数据准备耗时
| 元数据SQL合并 | 空表库全库schema-only | 192.759 s | 对象=10000
| 元数据SQL合并 | 空表库单表schema-only | 1.691 s | 指定1表/库内10000表
1000 4秒 VS 10000张表 192秒。
对于存储过程依赖的补充测试,在有大量plsql对象的库里新创建一张只有一个字段的空表,再gs_dump导出单张表,耗时42秒
gs_dump test_meta_complex -t public.t
....
....这里狂刷屏
....
gs_dump[user='gaussdb'][localhost][port='5432'][sorter][2026-08-07 04:08:57]: WARNING: could not resolve dependency loop among these items:
gs_dump[user='gaussdb'][localhost][port='5432'][sorter][2026-08-07 04:08:57]: FUNCTION f_100 (ID 11459 OID 424837)
gs_dump[user='gaussdb'][localhost][port='5432'][sorter][2026-08-07 04:08:57]: PACKAGE pkg_85 (ID 35869 OID 424737)
gs_dump[user='gaussdb'][localhost][port='5432'][sorter][2026-08-07 04:08:57]: PRE-DATA BOUNDARY (ID 35872)
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 04:08:57]: The total objects number is 480.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 04:09:05]: [100.00%] 480 objects have been dumped.
--
-- GaussDB database dump
--
SET statement_timeout = 0;
SET session_timeout = 0;
SET idle_in_transaction_timeout = 0;
SET xmloption = content;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET session_replication_role = replica;
SET enable_extension = on;
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 04:09:05]: WARNING: Extension is not a secure feature, and it may cause unexpected errors.
SET client_min_messages = warning;
SET nls_date_format = 'YYYY-MM-DD HH24:MI:SS BC';
SET search_path = public;
SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: t; Type: TABLE; Schema: public; Owner: gaussdb; Tablespace:
--
BEGIN;
CREATE TABLE public.t (
a integer
)
WITH (orientation=row, compression=no, storage_type=USTORE, segment=off);
ALTER TABLE public.t OWNER TO gaussdb;
COMMIT;
--
-- Data for Name: t; Type: TABLE DATA; Schema: public; Owner: gaussdb
--
COPY public.t (a) FROM stdin;
\.
;
--
-- GaussDB database dump complete
--
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 04:09:05]: dump table public.t successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 04:09:05]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 04:09:05]: total time: 42863 ms
也就是导出的流程还是和原本一样,需要先做全库的依赖排序,尽管指定的这个表并不存在其他依赖关系(实际上还是会有type/namespace/authid等依赖)。
SELECT classid, objid, refclassid, refobjid, deptype FROM pg_catalog.pg_depend WHERE deptype != 'p' AND deptype != 'e' AND deptype != 'c' ORDER BY 1,2
由于在这种场景下并没有优化,因此在指定导出单张表时,最好不要使用gs_dump,而是要用pg_get_tabledef导出DDL,然后用copy导出数据,这样更快。
测试一下超多表的情况下,并行是否能提升性能
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_meta_merge -F d -j 4 --disable-inter-table-parallel -f meta4
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:20:30]: The total objects number is 20479.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:20:41]: [ 48.83%] 10000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:20:41]: [ 97.66%] 20000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:20:41]: [100.00%] 20479 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:20:43]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:20:43]: total time: 85478 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_meta_merge -F d -j 8 --disable-inter-table-parallel -f meta8
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:22:49]: The total objects number is 20479.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:23:00]: [ 48.83%] 10000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:23:00]: [ 97.66%] 20000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:23:00]: [100.00%] 20479 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:23:01]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:23:01]: total time: 86939 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_meta_merge -F d -j 8 -f meta8_1
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:24:47]: The total objects number is 20479.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:25:00]: [ 48.83%] 10000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:25:01]: [ 97.66%] 20000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:25:01]: [100.00%] 20479 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:25:01]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:25:01]: total time: 103226 ms
[gaussdb@c93206eee3b8 gs_dump_507_test]$ gs_dump test_meta_merge -F d -j 4 -f meta4_1
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:35:44]: The total objects number is 20479.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:35:57]: [ 48.83%] 10000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:35:58]: [ 97.66%] 20000 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:35:58]: [100.00%] 20479 objects have been dumped.
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:35:59]: dump database successfully
gs_dump[user='gaussdb'][localhost][port='5432'][2026-08-07 06:35:59]: total time: 100663 ms
这个测试可以看出表多且没有数据的时候,开并发是没有性能提升的,而且如果不关闭表内并行,性能甚至会更差。也就是说,没有超大表时,用表间并行即可,有超大表时才要开表内并行。
对于客户而言,除了并行有非常明显的收益以外,元数据查询的优化似乎没得到期望中的效果,可能相比之前性能是有提升,但对于客户而言,导出耗时里仍然还是包含了大量的"无用功时间"。
其他
至于不导出失效视图的测试,测试结论就是,对于失效视图
- 加参数
--ignore-invalid-views, 不导出失效视图,日志NOTICE: options --ignore-invalid-views is set, ignore invalid view v1 with oid 458867 - 不加参数
--ignore-invalid-views,导出失效视图,不报错不中断 ,日志WARNING: Dump invalid view v1 with oid 458867
谓词过滤导出也是符合预期的,我也不贴测试结果了。
总结
GaussDB 507内核版本gs_dump使用建议
- 性能方面:
- gs_dump空库底噪2~3秒,无论是否有需要导出的东西
- 存在超大表,开并行,不关闭表内并行
- 表非常多,无超大表,开并行,并关闭表内并行
- 表非常多,无存储过程,导出单张表或少量表,只有底噪的额外影响
- 表非常多,无存储过程,导出所有表,每张表附加新的底糙,性能很差,表越多,性能指数级下降,并行无法减少底噪耗时开销,因为并行是针对数据导出阶段,而查元数据本身没有并行,建议分批导出
- 存储过程非常多,会加大底噪,导出单张表或少量表会浪费很多时间,不如写sql脚本分别导出表定义和表数据
- 导出范围控制:
- 谓词过滤:可以针对表使用谓词过滤条件,导出前可以一次性写好哪些大表的历史数据不导出,方便用于测试环境
- 失效视图:根据需要选择是否导出失效视图,因为失效视图在部分版本上可能会导入报错。

