Aekor

Aekor
专注于用户阅读体验的响应式博客主题
  1. 首页
  2. Oracle 数据库
  3. 正文

Oracle 数据泵实战:19c 到 11g 单表迁移、任务终止与结果导出

2026-02-22 16146点热度 0人点赞 0条评论

把一张表从 19c 迁到 11g,难点不在 expdp 语法,而在三件事:dump 必须是 11g 能读的版本;终端里 ctrl+C 之后作业可能还在跑;导入改名、排除统计信息要一次写对。下面按“导出前核对、源端导出、目标端导入、导入后校验、异常终止、结果集导出”的顺序给出可复制的命令。

一、场景与前提

源端是 19c RAC,目标端是 11g 单机,只迁 FAM.MY_PERSON 一张表,导入后改名为 MY_PERSON20260122。高版本 expdp 默认写新格式的 dump,11g 的 impdp 读不了,所以导出时必须显式指定 VERSION=11.2.0.4.0。这个值不能高于源库版本;目标库版本必须不低于这个值。

两个前提常被忽略:目录对象指向数据库服务器上的路径,不是客户端路径;RAC 下每个可能运行 worker 的节点都要能看到同一目录,否则作业切到另一实例会报目录不存在。

二、导出前先核对表结构

跨版本迁移失败,常见原因不是 expdp 写错,而是目标端根本没有对应的类型或长度。导出前把 DDL 拉出来看一眼,比导完再回滚便宜得多。

set long 200000
set pagesize 0
select dbms_metadata.get_ddl('TABLE','MY_PERSON','FAM') from dual;

重点看四类:字段类型是否 11g 支持(如 12c 之后的 IDENTITY 列、VARCHAR2 超过 4000 字节的扩展长度);有无虚拟列、不可见列;分区方式是否一致;表上是否有 11g 不认识的压缩或加密选项。

依赖对象也要确认,否则表过去了、索引和约束没过去,应用照样跑不起来:

select object_type, count(*)
from dba_objects
where owner = 'FAM'
  and object_name = 'MY_PERSON'
group by object_type;

select index_name, index_type, status
from dba_indexes
where table_owner = 'FAM' and table_name = 'MY_PERSON';

EXCLUDE=STATISTICS 只排除了统计信息,索引和约束默认还是会导。如果目标端已经有同名对象,导入时会报 ORA-00955 或 ORA-39151,这时才需要 EXCLUDE=INDEX,CONSTRAINT 逐个排除。

三、源端 19c:建目录、导出

3.1 看表有多大

select owner, sum(bytes/1024/1024/1024) GB
from dba_segments
where owner in ('FAM')
  and segment_name in ('MY_PERSON')
group by owner;

列名写成 onwer 会直接报 ORA-00904,正确写法是 owner。分区表在 dba_segments 里有多行,sum 正好把各分区加起来;结果为空时先确认表名大小写和 owner,segment_name 存的是大写。

3.2 确认目录对象

set linesize 300
set pagesize 300
col DIRECTORY_NAME for a30
col DIRECTORY_PATH for a50
select * from dba_directories;

DIRECTORY_PATH 必须以斜杠结尾,并且 oracle 用户对该路径有读写权限。目录对象只是给数据库一个“别名”,不会帮你创建 OS 目录。

3.3 创建目录并授权

create directory dump as '/oracle/app/db/dump/';
grant read,write on directory dump to public;

grant ... to public 省事,但生产环境建议只授给执行导出的账号,例如:

grant read,write on directory dump to fam;

3.4 执行导出

expdp 'userid="/as sysdba"' dumpfile=FAM_MY_PERSON20260122.dmp logfile=FAM_MY_PERSON20260122.log directory=DUMP tables=FAM.MY_PERSON parallel=4 COMPRESSION=all VERSION=11.2.0.4.0

参数逐个说明:

userid="/as sysdba" 表示以 SYSDBA 执行。普通用户执行时要有表的读权限和目录读写权限;导出整库或 schema 还需要 EXP_FULL_DATABASE。

directory=DUMP 用的是目录对象名,不是路径。dumpfile 和 logfile 只写文件名,实际落在 DIRECTORY_PATH 下。

tables=FAM.MY_PERSON 指定单表。表名带 schema,避免依赖当前用户。

parallel=4 是并行度。实际能跑多少受表/分区数、CPU、I/O 和 dumpfile 数量影响,以日志里的 worker 数和完成时间为准。单表导出时,如果表没有分区、也没有二级索引并行,4 个 worker 里可能只有 1 个在干活。多个 worker 要各自写独立的文件才跑得起来,文件名用模板:

dumpfile=FAM_MY_PERSON20260122_%U.dmp

只给一个固定文件名时,并行度往往跑不满。也可以显式列出多个文件名,效果一样。

COMPRESSION=all 同时压缩数据和元数据。压缩会消耗 CPU,换取更小的 dump 和更少的传输时间;企业版使用 Data Pump 压缩前要确认 Advanced Compression 选件许可。跨版本迁移时还要确认目标端的 impdp 支持压缩 dump;COMPRESSION 与 VERSION 的组合有版本前提,正式导之前先在测试库完整导一次。

VERSION=11.2.0.4.0 是跨版本迁移的关键:让 19c 按 11.2.0.4 格式写 dump,并限制使用 11g 不认识的新特性。但源表若用了 19c 独有的数据类型,导入仍会失败,导出前先核对表结构。

导出结束后先看日志末尾是否有 successfully completed,再看有没有 ORA- 错误。dump 文件大小、日志里的对象列表和行数,都是后面导入验收的基准。

RAC 下还要确认 dump 文件落在共享存储上。目录指向本地文件系统时,作业切到另一实例会报 ORA-39070(无法打开日志文件)或 ORA-39087(目录名无效),看着像权限问题,实际是节点看不到文件。

ls -l /oracle/app/db/dump/
df -h /oracle/app/db/dump/

空间按“原表大小 × 压缩比 + 余量”估算;写满目录时作业会挂起,而不是立刻报错。

四、目标端 11g:建目录、导入、改名

4.1 确认目录对象

set linesize 300
set pagesize 300
col DIRECTORY_NAME for a30
col DIRECTORY_PATH for a50
select * from dba_directories;

4.2 创建目录并授权

create directory dump as '/oracle/app/db/dump/';
grant read,write on directory dump to public;

目标端的路径可以同名,也可以不同名;关键是 directory 对象指向的路径里确实放着从源端传过来的 dmp 文件。传文件用 scp/sftp 均可,传完核对大小和校验和,避免半包:

md5sum FAM_MY_PERSON20260122.dmp

两端结果一致再开始导入。dump 文件被截断时,impdp 不一定直接说“文件不完整”,常见的是 ORA-39002(无效操作)或 ORA-39070,所以校验和这一步不能省。

4.3 执行导入

impdp 'userid="/ as sysdba"' dumpfile=FAM_MY_PERSON20260122.dmp logfile=impdp_FAM_MY_PERSON20260122.log directory=dump REMAP_TABLE=FAM.MY_PERSON:MY_PERSON20260122 parallel=4 EXCLUDE=STATISTICS,PROCACT_INSTANE

REMAP_TABLE=FAM.MY_PERSON:MY_PERSON20260122 把源表映射成新表名。新名不带 schema,表示仍然导入到 FAM 用户下;如果目标端 schema 不同,要再加 REMAP_SCHEMA=FAM:NEWOWNER,否则会因为目标用户不存在而失败。

EXCLUDE=STATISTICS 不导入统计信息。跨版本统计信息本来就不一定适用,导入后重新收集更稳妥:

exec dbms_stats.gather_table_stats('FAM','MY_PERSON20260122');

收集时注意 cascade:默认只收表级统计信息,索引统计信息可能还是空的,需要索引统计时加 cascade => TRUE。大表上还要控制 degree,别让并行收集把 CPU 打满。

参数里的 PROCACT_INSTANE 疑似是 PROCACT_INSTANCE 的拼写错误。这个对象类型名建议先在目标端用 impdp ... help=y 或按版本文档确认,再决定是否保留;名字不合法时,impdp 会在解析参数阶段直接报错。

导入前确认目标表不存在。同名表已存在时默认报 ORA-39151 并跳过;需要覆盖或追加时显式加 TABLE_EXISTS_ACTION=TRUNCATE 或 APPEND,不要靠默认值猜。

导入阶段常见的几个报错,基本都能从日志第一行定位:

ORA-39002  invalid operation
ORA-39070  Unable to open the log file
ORA-39087  Directory name DUMP is invalid
ORA-39151  Table "FAM"."MY_PERSON" exists(table_exists_action 为 skip)
ORA-12899  value too large for column
ORA-01950  no privileges on tablespace

ORA-39070/ORA-39087 查目录对象和 OS 权限;ORA-39151 是目标表已存在;ORA-12899 是两端长度语义不同(byte 与 char);ORA-01950 是目标用户在该表空间没有配额。

REMAP_TABLE 只改表名,不会自动改索引、约束的名字。如果目标 schema 里已经有同名索引,可能报 ORA-00955(名称已被现有对象占用),这时要先确认冲突对象,再决定改名或删除。

只要数据不要索引和约束,用 CONTENT=DATA_ONLY 跳过元数据;只要结构不要数据,用 CONTENT=METADATA_ONLY。不要和 EXCLUDE 重复设置,容易互相覆盖。

impdp ... CONTENT=DATA_ONLY

表上有 LOB 字段时,还要确认目标端 LOB 存储参数和 MAX_STRING_SIZE,跨大版本时这两处最容易出问题。

五、导入之后先别急着交付

导入成功不等于迁移完成。目标端 11g 的单表迁移,交付前至少还要确认三件事,而且都要在业务连上来之前做。

先确认对象数量对得上。表、索引、约束、触发器的数量,两端应该一致(REMAP_TABLE 只改表名,不会增加或减少对象):

select object_type, count(*)
from dba_objects
where owner = 'FAM'
  and object_name in ('MY_PERSON','MY_PERSON20260122')
group by object_type;

再确认索引真的可用。跨版本导入后索引状态可能是 UNUSABLE,尤其是分区索引或函数索引:

select index_name, status, num_rows, last_analyzed
from dba_indexes
where table_owner = 'FAM' and table_name = 'MY_PERSON20260122';

UNUSABLE 的索引不会报错,但查询会走全表扫描,业务方只会说“变慢了”。重建索引用 alter index ... rebuild,大表上要考虑并行度和临时表空间。

最后抽样比对数据。行数一致只能说明条数对,不能说明内容对。按主键抽几条,两端各查一次:

select * from FAM.MY_PERSON20260122 where rownum <= 5;

字符型字段重点看中文和特殊字符,跨字符集迁移出问题时,往往就是某几个字变成了问号。

六、ctrl+C 之后,作业其实还在跑

这是 expdp 最常见的一个坑:在终端按 ctrl+C,客户端退出了,但数据库里的 Data Pump 作业还在执行,甚至还在写 dump 文件。

expdp 客户端只负责提交作业和显示进度,真正干活的是数据库里的 master 进程和一组 worker(DM00、DW00…)。ctrl+C 只断开客户端与 master 的连接,master 收不到指令就继续跑,状态从 EXECUTING 变成 IDLING,等你 attach 回来。

所以判断作业是否结束,不能看终端有没有退回 shell,只能看 DBA_DATAPUMP_JOBS。停机窗口里尤其要注意:以为停了就开始切库,dump 文件还在被写,恢复出来的文件不可用。

6.1 先看作业状态

select job_name, state from dba_datapump_jobs;

输出示例:

JOB_NAME                       STATE
------------------------------ ------------------------------
SYS_EXPORT_TABLE_02            EXECUTING
SYS_EXPORT_TABLE_01            NOT RUNNING

EXECUTING 表示还在跑;IDLING 表示 worker 暂时空闲但在等客户端;NOT RUNNING 才是已经停止。只要还能看到 EXECUTING,就不要删 dump 文件,也不要重启实例。

6.2 attach 到作业

expdp oimuser/szeq##22d ATTACH=SYS_EXPORT_TABLE_02

attach 的账号要有权限操作该作业:作业是谁建的,就用谁或同等权限的账号。示例作业 owner 是 DEV_OIM,用 oimuser 能 attach 说明现场权限已配好,换环境不要照抄账号。

attach 成功后会看到作业参数、已处理字节数、完成百分比和当前状态:

Job: SYS_EXPORT_TABLE_02
  Owner: DEV_OIM
  Operation: EXPORT
  Creator Privs: FALSE
  GUID: 0D61AEFBC5E63053E0631C24000A235D
  Start Time: Tuesday, 26 December, 2023 11:14:29
  Mode: TABLE
  Instance: idm1
  Max Parallelism: 1
  State: IDLING
  Bytes Processed: 120,615,014,584
  Percent Done: 38
  Current Parallelism: 1
  Job Error Count: 0
  Dump File: /backup/dumpdata/provision.dmp
    bytes written: 123,126,849,536
Worker 1 Status:
  Process Name: DW00
  State: UNDEFINED
Export> 

6.3 停止作业

在 Export> 提示符下执行:

stop_job=immediate

系统会再确认一次:

Are you sure you wish to stop this job ([yes]/no): yes

stop_job=immediate 尽快停止 worker 但保留现场,之后还能 start_job 续跑;确定永不再需要才用 kill_job,它会连主表一起清掉。生产库上先想清楚再用。

stop_job 之后作业还在,DBA_DATAPUMP_JOBS 能看到,dump 文件保留,可以接着导;kill_job 是彻底放弃,主表被删,已写出的 dump 成了无法续传的碎片。

attach 不上时(客户端已退出、密码不明),先确认作业是否还有客户端附着,再决定下一步:

select job_name, owner_name, state, attached_sessions
from dba_datapump_jobs;

ATTACHED_SESSIONS 大于 0 说明还有客户端连着,先让它断开。此时不要直接 drop 主表:作业进程还在的话,主表删不掉,或者删了之后 worker 继续写 dump,留下一个谁也说不清状态的作业。正确顺序是先让作业停下(attach 后 stop_job,或由 DBA 按现场流程终止 master 进程),确认 DBA_DATAPUMP_JOBS 里没有该作业,再清理主表。

6.4 确认真的停了

select job_name, state from dba_datapump_jobs;

输出:

JOB_NAME                       STATE
------------------------------ ------------------------------
SYS_EXPORT_TABLE_02            NOT RUNNING
SYS_EXPORT_TABLE_01            NOT RUNNING

状态变成 NOT RUNNING 才算结束。注意 NOT RUNNING 有两种含义:正常完成,和被 stop 后停在半路。前者日志末尾有 successfully completed,后者只有 Job stopped 之类的中断记录,两者不能混为一谈。

如果作业已经 NOT RUNNING 但主表还留在数据字典里,确认不再需要后,在作业 owner 的 schema 下清理。先查出确切的表名和 owner,不要凭作业名猜:

select owner, table_name, status
from dba_tables
where table_name like 'SYS_EXPORT_%';

确认没有其他作业在用之后,再执行:

drop table "SYS_EXPORT_TABLE_02";

这是不可逆操作,执行前确认作业名、owner 和是否还要续跑。不要在生产库上凭记忆删 SYS_EXPORT_* 表。

七、SQL*Plus 把结果导出成 txt/xls/html

Data Pump 解决的是数据迁移,日常还有一类需求:把查询结果落成文件,交给开发、审计或 Excel。SQL*Plus 的 SPOOL 配合 SET 命令就够了,不需要额外工具。

7.1 导出成可执行的 SQL 脚本

set feedback off
set pagesize 0
set long 90000
spool /home/oracle/test.sql
set pagesize 9999
SELECT 'Alter Sequence '||sequence_owner||'.'|| SEQUENCE_NAME || ' Increment By ' || INCREMENT_BY ||';' from DBA_SEQUENCES
WHERE SEQUENCE_OWNER in ('TEST');
exit;
spool off

这段把 DBA_SEQUENCES 里的序列拼成一条条 ALTER SEQUENCE ... INCREMENT BY ...;,spool 成 .sql 文件后可直接拿到目标库执行。

set pagesize 0 关闭表头和分页,set long 90000 防止 LONG/CLOB 被截断,set feedback off 去掉“已选择 N 行”。注意 spool 之后再写 set pagesize 9999 会把表头重新打开;要纯净 SQL 就保持 pagesize 0 并加 set heading off。

另外,exit 之后的 spool off 不会执行,因为会话已经退出。SQL*Plus 退出时会关闭 spool 文件,所以文件仍会生成;更严谨的写法是把 spool off 放在 exit 之前。

7.2 导出成纯文本

SET ECHO OFF
SET FEEDBACK OFF
SET PAGESIZE 0
SET TERMOUT OFF
SET TRIMS ON
SET LINESIZE 600
SET HEADING OFF
SPOOL /home/oracle/test.txt
SELECT 'Alter Sequence '||sequence_owner||'.'|| SEQUENCE_NAME || ' Increment By ' || INCREMENT_BY ||';' from DBA_SEQUENCES
WHERE SEQUENCE_OWNER in ('TEST');
EXIT;
SPOOL OFF

TERMOUT OFF 让结果只进文件、不刷屏,适合放到脚本里跑。TRIMS ON 用来减少行尾空格;如果下游对行尾空格敏感,再确认 TRIMSPOOL 的设置,不同 SQL*Plus 版本对 TRIMS/TRIMSPOOL 的行为略有差异。

纯文本导出常遇到两个问题:LINESIZE 小于实际行宽导致 SQL 从中间断开,拿到目标库执行报语法错误;PAGESIZE 0 与 NEWPAGE 组合在文件末尾留下空行,下游按行解析时当成记录。导出后用 wc -l 和 tail 看一眼再交付。

LINESIZE 600 要大于最宽的一行,否则会被折行。拼接出来的 SQL 如果很长,先把 LINESIZE 调大,或者用 COL ... FOR A... 控制列宽。

7.3 导出成 xls

set linesize 300
set term off verify off feedback off pagesize 999
set markup html on entmap ON spool on preformat off
spool test.xls
SELECT 'Alter Sequence '||sequence_owner||'.'|| SEQUENCE_NAME || ' Increment By ' || INCREMENT_BY ||';' from DBA_SEQUENCES
WHERE SEQUENCE_OWNER in ('TEST');
exit;
spool off

生成的实际是 HTML 表格,只是扩展名写成 .xls,Excel 能直接打开。它不是二进制 xls,没有公式和多 sheet;要真正的 xlsx 请用 Python/Java 或 APEX。

SET MARKUP HTML ON 打开 HTML 标记,ENTMAP ON 转义特殊字符,PREFORMAT OFF 让 SQL*Plus 按表格而不是预格式文本输出。Excel 打开时可能提示“文件格式和扩展名不匹配”,选“是”即可。

7.4 导出成 html 汇总

set markup html on spool on
spool db_parameter.html
set pagesize 9999
select * from dba_profiles where profile='DEFAULT';
select username,profile,account_status from dba_users;
select * from dba_sys_privs;
select * from user_sys_privs;
select value from v$parameter where name='audit_trail';
select value from v$parameter where name='audit_sys_operations';
select value from v$parameter where name='audit_file_dest';
select * from dba_registry_history;
exit;
spool off

这组查询适合做配置快照:默认 profile、用户状态、系统权限、审计参数、补丁历史落在一个 HTML 里,交付或比对都方便。多个 select 依次追加到同一文件,不必单独 spool。

SET MARKUP HTML ON 之后,SQL*Plus 给每个结果集生成一个表格并在文件头写样式。要边框可用 SET MARKUP HTML ON TABLE 'border="1"',要固定显示空值用 SET NULL 'NULL'。

7.5 字符集、路径与文件大小

spool 出来的文件在文件系统上就是一个普通文本或 HTML 文件,交付前顺手看一下大小和编码,能省掉对方打不开的来回沟通。

ls -lh test.txt db_parameter.html
file test.txt

file 显示 UTF-8 Unicode text 说明编码正确;显示 ISO-8859 text 或 Non-ISO extended-ASCII 基本可以确定是 NLS_LANG 配错,文件里的中文已经损坏,重新导出比转换编码可靠。

文件超过几十 MB 时,Excel 打开 xls(其实是 HTML)会很慢,甚至直接卡死。这种量级更适合直接给 CSV 或走数据库导出,不要用 spool。

spool 的相对路径落在 SQL*Plus 的当前工作目录,不是 $ORACLE_HOME。脚本里尽量写绝对路径,避免换一个目录执行就找不到文件。

批量脚本最好用带时间戳的文件名,或先删旧文件。同名文件在多次执行之间的行为容易让人误判,尤其在自动化任务里,拿到旧文件当新结果的事故并不少见。

中文乱码通常是客户端 NLS_LANG 与数据库字符集不匹配,不是 spool 的问题。先确认:

select value from nls_database_parameters where parameter='NLS_CHARACTERSET';

客户端环境变量按实际字符集设置,不要把 AL32UTF8 的库硬配成 ZHS16GBK。

八、时间与空间怎么估

停机窗口里最容易翻车的是“以为两小时能导完”。估算分三步,都用现成数据,不需要额外工具。

先看表的真实大小,不看 dba_tables.blocks,那个值可能过期:

select segment_name, segment_type, bytes/1024/1024/1024 GB
from dba_segments
where owner = 'FAM' and segment_name = 'MY_PERSON'
order by bytes desc;

再看最近一次全表扫描的耗时,作为 I/O 吞吐的参考:

select sql_id, elapsed_time/1000000 sec, executions, buffer_gets, disk_reads
from v$sql
where sql_text like '%MY_PERSON%'
  and sql_text not like '%v$sql%'
order by elapsed_time desc
fetch first 10 rows only;

11g 不支持 fetch first,换成 rownum <= 10 的子查询。

最后按经验比例折算:导出通常是“读全表 + 写 dump”,压缩开启后 CPU 会成为瓶颈;导入是“读 dump + 写表 + 建索引”,如果索引多,建索引的时间可能超过插数据。

空间要同时算三份:源端 dump 目录、传输中转目录、目标端 dump 目录。压缩比按 2:1 到 4:1 估,字符型数据多时压缩率高,已经压缩过的二进制(BLOB 图片、PDF)几乎压不动。宁可多留一倍余量,也不要在窗口中间去扩文件系统。

九、验收清单

导入完成后至少核对四件事:impdp 日志末尾是否成功;两端行数是否一致;无效对象数量是否异常;统计信息是否已重新收集。

行数核对要注意口径。count(*) 走全表扫描,大表上很慢;如果表有主键且统计信息新鲜,可以先用 dba_tables.num_rows 粗看,再用 count(*) 精确核对一次。两边都查,别只查目标端:

select table_name, num_rows, last_analyzed
from dba_tables
where owner = 'FAM' and table_name in ('MY_PERSON','MY_PERSON20260122');

last_analyzed 为空说明统计信息还没收集,num_rows 不可信。

无效对象要分清是“本来就无效”还是“导入后变无效”。导入前在目标端记一份基线,导入后对比差值:

select owner, object_type, count(*)
from dba_objects
where status = 'INVALID'
group by owner, object_type
order by 3 desc;

单表迁移一般不会产生大量无效对象。如果突然出现几十个,先看是不是同义词或视图指向了不存在的表。

行数一致不代表数据完全一致,但对单表迁移来说是最低成本的校验。如果表上有 LOB、分区或触发器,还要单独确认这些对象是否导入成功。统计信息没重新收集时,执行计划可能沿用导入前的旧值,上线前跑一次 gather_table_stats 更稳。

勘误与待核对

  • 表大小查询里的 onwer 是笔误,文中按 owner 给出。
  • EXCLUDE=STATISTICS,PROCACT_INSTANE 中的 PROCACT_INSTANE 疑似拼写错误,需按目标端 impdp help=y 确认合法对象类型。
  • 单 dumpfile 配 parallel=4 时实际生成几个文件、并行度是否跑满,以导出日志为准;必要时改用带 %U 的文件名模板。
  • impdp 的 userid="/ as sysdba" 中间有一个空格,文中保留原样;如果现场报错,改成 /as sysdba。
  • 目标端是否已存在 FAM 用户、表空间和同名索引,需在导入前确认。
  • 导出与导入的实际耗时、dump 压缩比,需按现场数据实测,本文给的只是估算方法。
  • 11g 目标端的字符集必须与源端兼容(子集关系),否则中文会变成问号;导入前用 select value from nls_database_parameters where parameter='NLS_CHARACTERSET'; 两端各查一次。

原文首发于微信公众号「止水研习社」。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Oracle 数据泵 数据迁移
最后更新:2026-10-17

Aekor

这个人很懒,什么都没留下

点赞
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

使用AI教程

  • API报错解决方案
  • API 基础知识
  • API Key 获取
  • 最新接入教程

分类

  • Blog
  • Oracle 数据库
  • TradingAgents-CN
  • 使用教程
  • 数据库

COPYRIGHT © 2026 Aekor. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang