目 录CONTENT

文章目录

【GaussDB】507版本gs_dump功能更新

DarkAthena
2026-08-09 / 0 评论 / 0 点赞 / 5 阅读 / 0 字

【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.3226.861.0
内核版本505.2.1.SPC0800507.0.0
URL路径/tg-cent/gaussdb-38-0012.html/rf-cent/gaussdb-38-0940.html
文档分类工具参考(集中式)参考(集中式)
内容长度~20,234 字符~24,244 字符
版权年份20242024

一、工具介绍部分

差异项旧版 (25.1.32)新版 (26.861.0)
默认数据库描述"支持导出的数据库可以是默认数据库postgres""支持导出的数据库可以是默认数据库"(去掉了具体名称)
归档格式导入工具说明"使用gs_restore可以选择要从自定义归档/目录归档/tar归档导出文件中导入相应的数据库对象""这三种归档格式,必须使用5.7.5-gs_restore进行对象和数据的导入。gs_restore也可以选择要导入的数据库对象"

二、注意事项部分(变化最大)

新增的注意事项(旧版没有,新版新增)

  1. CREATE EVENT定时任务检查:通过CREATE EVENT语法创建的定时任务若无法被导出,请检查gs_job_attribute表中定时任务job_style属性是否为EVENT
  2. 触发器导出要求:当导出对象中包含触发器时,需要加上参数--use-set-session-authorization --all,并通过文本模式导出
  3. model对象:使用gs_dump不会转储model对象
  4. 系统管理员导出限制:系统管理员导出时不会导出初始用户创建的对象,需使用初始用户进行导出
  5. 依赖PACKAGE内部函数的视图:首次导入目标端时会报错,需使用gs_dump --schema-only备份元数据再次导入
  6. 高级压缩库级策略定义:需全库导出且系统管理员权限,否则策略以表/分区级独立策略形式导出
  7. 间隔分区表:只能导出range分区部分,不能导出interval分区部分
  8. ddl_invalid_mode=invalid的影响:函数和包drop操作时不级联删除,导出时会因依赖关系找不到对象而报错
  9. 失效视图:默认导出失效视图,可指定--ignore-invalid-views不导出
  10. rowid系统列:不导出rowid系统列上的数据,仅导出rowid作为数据类型时用户列的数据
  11. M-Compatibility零字符截断:含零字符('\0')数据进行gs_dump操作时存在数据截断

删除的注意事项(旧版有,新版去掉)

  1. gs_dump时生成列不会被转储(已删除)
  2. 初始用户创建的表上含用户自定义函数的表达式索引,系统管理员导出后需用初始用户导入(已删除)

修改的注意事项

项目旧版新版
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-transactionDDL语句不再被额外包裹在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) 主要有以下方向的增强:

  1. 并行导出能力:新增 -j/--jobs--disable-inter-table-parallel 等并行导出参数,支持表内并行和表级别并行
  2. 谓词过滤导出:新增 --query--include-query-file 参数,支持按条件导出部分表数据
  3. 数据文件格式:新增 --with-copy-format 支持 CSV 格式导出
  4. 失效视图处理:新增 --ignore-invalid-views 参数
  5. 事务控制:新增 --no-transaction 参数
  6. 日志级别:新增 --log-level 参数
  7. 注意事项大幅扩充:新增间隔分区表、触发器导出、高级压缩策略、rowid系统列等十余条注意事项
  8. 锁机制描述更精确:从"共享锁"改为"ACCESS SHARE级别锁",并补充锁冲突参考

分析文档差异

从文档里的修改点来看,算是非常扣细节了,个人猜测要么是请了个有强迫症(褒义)的文档专家,要么就是用了AI。

除了官方产品文档上体现的差异,还有一个点仅体现在版本说明书里

3.版本号、兼容性等重复查询SQL归一化复用优化;对函数、视图、表等容易出现超多对象的类型在dump过程中的sql进行分析合并,减少SQL执行次数。

这个点其实很重要,因为实践中经常会遇到,要导出指定的一个表,gs_dump元数据查询处理用了10分钟,然后实际对于这个表的导出本身,只用了1秒。这是PG系一直饱受诟病的依赖对象解环排序处理所导致的。即就算指定了要导出的对象,也仍然会扫描库中所有的对象,识别依赖关系去进行排序。当对象多、依赖关系复杂时,这个处理过程就会非常慢。不过我暂不确定GaussDB 507版本的这个优化效果到底怎样,但至少华为是有行动了。

综合以上内容,个人判断,对于一个正常的用户环境,历史上用户最关心的两个问题--
gs_dump的导出性能和导出范围控制,在GaussDB 507 版本上都得到了加强。其中最为重要的为以下三个能力

  1. 并行导出(性能)
  2. 元数据查询SQL合并(性能)
  3. 谓词过滤导出(导出范围控制)
  4. 不导出无效视图(导出范围控制)

大概设计几个测试场景

  • 并行导出(建新库)

    • 一张表十个字段百万行 并行 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_j4

1.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.sql

2.2 空表库全库 schema-only 导出

rm -f meta_empty_all.dmp && time gs_dump test_meta_merge -F c -s -f meta_empty_all.dmp

2.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.dmp

2.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.sql

2.6 执行复杂对象创建

gsql -d test_meta_complex -f gen_complex_objects.sql

2.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.sql

3.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.sql

3.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使用建议

  • 性能方面:
  1. gs_dump空库底噪2~3秒,无论是否有需要导出的东西
  2. 存在超大表,开并行,不关闭表内并行
  3. 表非常多,无超大表,开并行,并关闭表内并行
  4. 表非常多,无存储过程,导出单张表或少量表,只有底噪的额外影响
  5. 表非常多,无存储过程,导出所有表,每张表附加新的底糙,性能很差,表越多,性能指数级下降,并行无法减少底噪耗时开销,因为并行是针对数据导出阶段,而查元数据本身没有并行,建议分批导出
  6. 存储过程非常多,会加大底噪,导出单张表或少量表会浪费很多时间,不如写sql脚本分别导出表定义和表数据
  • 导出范围控制:
  1. 谓词过滤:可以针对表使用谓词过滤条件,导出前可以一次性写好哪些大表的历史数据不导出,方便用于测试环境
  2. 失效视图:根据需要选择是否导出失效视图,因为失效视图在部分版本上可能会导入报错。
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin
博主关闭了所有页面的评论