一.迁移需求
KDTS工具属于电科金仓旗下,支持同构和异构商用/国产数据库之间的数据全量、增量迁等迁移,该工具是通过WEB界面进行可视化操作、完全免费。本文采用V009R001C002B0014版本中的新迁移工具KDTS进行异构数据库间数据迁移。
采用思路:
- 本地部署V009R001C002B0014版本的数据库,字符集都是UTF8,兼容模式Oracle,具体步骤省略
- 使用KDTS工具实现迁移
二.数据库信息
库类型 | 库架构 | 实例 | 端口 | 用户名密码 | 数据量 | ||
源库 | 192.168.3.191 | Oracle11.2.0.4 | 单点 | xjtopicis | 1521 | topicis/oracle | 13.66G |
目标库 | 192.168.3.175 | V009R001C002B0014 | 单点 | xjtopicis | 54323 | topicis/oracle |
三.迁移前准备
3.1.查数据库版本
3.1.1.源库Oracle
11.2.0.4单点
sqlplus -V
或
SELECT version FROM product_component_version WHERE substr(product, 1, 6) = 'Oracle';
VERSION
11.2.0.4.03.1.2.目标库KES
--查看数据库版本
select version(); --KingbaseES V009R001C002B0014 on x64, compiled by Visual C++ build 1800, 64-bit
或
--查进程
-bash-4.2$ ps -ef | grep kingbase
--查版本
-bash-4.2$ ksql -V
ksql (Kingbase) V009R001C002B00143.2.查字符集
3.2.1.源库Oracle
-- 查看数据库字符集
set linesize 999
col value for a60
select * from nls_database_parameters where PARAMETER in ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');
PARAMETER VALUE
------------------------------ ----------------------------------------------------------------------------
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET UTF8
select userenv('language') from dual;3.2.2.目标库KES
test=# \l+
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
-------------+------------+----------+-------------+-------------+---------------------------+---------+------------+-------------
test | system | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 8561 kB | KES_default |
| | | | | | | |
(1 row)3.3.查源库数据量Oracle
--查看总大小
select round(sum(bytes) / 1024 / 1024 / 1024, 2) || 'G'
from dba_segments
where owner in ('TOPICIS') ;
ROUND(SUM(BYTES)/1024/1024/1024,2)||'G'
-----------------------------------------
13.66G3.4.统计源库业务数据
--每个业务用户下的总对象数量校验
SELECT D.OWNER,COUNT(1)
FROM dba_objects d
WHERE d.OWNER in ('TOPICIS')
AND NOT EXISTS (SELECT 1 FROM DBA_RECYCLEBIN B WHERE B.object_name=D.OBJECT_NAME AND D.OWNER=B.owner)
GROUP BY D.OWNER
ORDER BY D.OWNER ;
OWNER COUNT(1)
------------------------------ ----------
ENTSERVICE 14163
--每个业务用户下的各个对象类别的数量校验
SQL> set pagesize 999
SQL> select OWNER,OBJECT_TYPE,status,count(OBJECT_NAME) from dba_objects where owner in ('TOPICIS') group by OBJECT_TYPE,owner,status order by 1,3,2;
OWNER OBJECT_TYPE COUNT(OBJECT_NAME)
------------------------------ ------------------- ------------------
ENTSERVICE SEQUENCE 6
ENTSERVICE LOB 7
ENTSERVICE INDEX 91
ENTSERVICE TABLE 123
--查询回收站lob对象数量(可选),lob数量不一致排查
select owner,type,count(*) from dba_recyclebin group by owner,type order by owner;
--数据量统计
----新增count_rows 函数
CREATE OR REPLACE FUNCTION count_rows (
table_name IN varchar2,
owner IN varchar2 := NULL
)
RETURN number AUTHID current_user
AS
num_rows number;
stmt varchar2(2000);
BEGIN
IF owner IS NULL THEN
stmt := 'select count(*) from "' || table_name || '"';
ELSE
stmt := 'select count(*) from "' || owner || '"."' || table_name || '"';
END IF;
EXECUTE IMMEDIATE stmt INTO num_rows;
RETURN num_rows;
END;
/
---调用count_rows 函数,统计各种表的记录数
select table_name, count_rows(table_name) nrows from user_tables where tablespace_name='TOPICIS'
order by nrows desc;3.5.目标库查兼容模式
test=# show database_mode;
database_mode
---------------
oracle
(1 行记录)
test=# show enable_ci; --默认off:区分大小写
enable_ci
-----------
off
(1 行记录)3.6.目标库创建用户和数据库
create user topicis with password 'oracle';
create database xjtopicis owner topicis;
grant all privileges on database xjtopicis to topicis;四.迁移过程
4.1.运行迁移web程序
该迁移场景本在金仓官网下载新版V009R001C002B0014金仓数据库并在Windows客户机上安装,使用是金仓库中自带的迁移工具web端
位置:E:\Program Files\Kingbase\ES\V9\KESRealPro\V009R001C002B0014\ClientTools\guitools\KDts\KDTS-WEB\bin
双击启动startup.bat
但是迁移报错,所以当下不建议用Windows环境下自带的KDTS迁移工具会出现以下报错(如果非要在Windows下用联系厂商获取单独的新版本KDTS工具),建议使用Linux环境下的KDTS。
Linux环境下KDTS路径:/home/kingbase/KESV9/KESRealPro/V009R001C002B0014/ClientTools/guitools/KDts/KDTS-WEB/bin
启动文件:双击启动startup.sh
启动过程如下:
web登录地址http://192.168.3.175:54523/ 账号密码默认(kingbase/kingbase),直接点登录即可


问题处理
问题描述
新版本KDTS启动提示如下报错:

shutdown.bat后重新进行startup.bat也不行
问题原因
和开发沟通,路径太复杂,或者有中文目录的时候就会找不到出现上图情况。只在windows下有这个问题,需要把KDTS目录往前提。
当前路径:E:\Program Files\Kingbase\ES\V9\KESRealPro\V009R001C002B0014\ClientTools\guitools\KDts\KDTS-WEB\bin
解决办法
将E:\Program Files\Kingbase\ES\V9\KESRealPro\V009R001C002B0014\ClientTools\guitools\KDts下的KDTS-WEB文件夹拷贝到E盘下启动正常。启动会提示如下报错,该报错会导致进入数据源列表一直转圈,当前已提bug

4.2.配置数据源
4.2.1.源数据库数据源

在列表中查看已创建数据源,如下:

4.2.2.目标库数据源

在列表中查看已创建数据源,如下:

4.3.创建迁移任务
4.3.1.选择数据源


4.3.2.选择模式
注意目标模式的选择,我这里是public模式,如果是自定义的模式,请注意更改

全选所有对象
4.3.3.选择迁移对象

4.3.4.配置迁移参数
这个地方务必注意

4.3.5.查看迁移结果

如果是迁移失败,可以点“二次迁移”会将第一次迁移失败的或者未迁移的数据进行迁移。
4.4.处理迁移报错
失败的脚本位置:安装目录下的\results\2024-12-03_02-59-37\TOPICIS\FailedScript
点开详情,查看迁移结果,对报错的进行处理

4.4.1.表结构报错处理
ERROR: 类型 "raw" 不存在报错及处理办法
查看报错日志
单击失败数查看详情
TOPICIS.CMP3$308925 fail:
com.kingbase8.util.KSQLException: ERROR: 类型 "raw" 不存在
Position: 3100 At Line: 2, Line Position: 53解决办法
--super用户的角色登录业务库
\c xjtopicis system
--创建扩展
create extension kdb_raw;


4.4.2.表数据失败处理
查看错误日志

解决办法
忽略该表,SYS_EXPORT_TABLE开头的表是Oracle中转储的记录表,KES中不需要,不用处理忽略即可。
4.4.3.索引报错处理
ERROR: 索引表达式中函数必需标记为 IMMUTABLE
查看错误日志
TOPICIS.IDX_REG_LICENSEISSUEINFO_TSP fail:
com.kingbase8.util.KSQLException: ERROR: 索引表达式中函数必需标记为 IMMUTABLE报错的sql_1
CREATE INDEX "idx_reg_licenseissueinfo_tsp_f1168aa4" ON "public"."reg_licenseissueinfo" ((TO_CHAR("TIMESTAMP",'YYYY-MM-DD HH24:MI:SS')) ASC);报错的sql_2
CREATE INDEX "idx_ecps_baseinfo_2013_numyear_4ecdbdd9" ON "public"."ecps_baseinfo_2013" ((TO_NUMBER("ANCHEYEAR")) ASC);解决办法
报错的sql_1的解决办法
--查看函数类型
xjtopicis=# \df+ to_char
函数列表
架构模式 | 名称 | 结果数据类型 | 参数数据类型 | 类型 | 挥发性 | 平行 | 拥有者 | 安全 | 存取权限 | 程序语言 | 原始程式 |
描述
------------+---------+--------------+-----------------------------------+------+----------+----------+--------+--------+----------+----------+---------------------------+-----------
------------------------------
pg_catalog | to_char | text | bigint, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | int8_to_char | format int
8 to text
pg_catalog | to_char | text | double precision, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | float8_to_char | format flo
at8 to text
pg_catalog | to_char | text | integer, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | int4_to_char | format int
4 to text
pg_catalog | to_char | text | numeric, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | numeric_to_char | format num
eric to text
pg_catalog | to_char | text | pg_catalog.interval, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | interval_to_char | format int
erval to text
pg_catalog | to_char | text | real, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | float4_to_char | format flo
at4 to text
pg_catalog | to_char | text | timestamp without time zone, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | timestamp_to_char | format tim
estamp to text
pg_catalog | to_char | text | timestamp with time zone, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | timestamptz_to_char | format tim
estamp with time zone to text
pg_catalog | to_char | text | time without time zone, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | time_to_char | format tim
e to text
pg_catalog | to_char | text | tinyint | 函数 | 不可更改 | 安全的 | system | 调用者 | | sql | select cast($1 as text) | convert ti
nyint to text
pg_catalog | to_char | text | tinyint, text | 函数 | 稳定 | 安全的 | system | 调用者 | | c | tinyint_to_char | format tin
yint to text
sys | to_char | text | bigint | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | boolean | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | boolean, text | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select text($1); +|
| | | | | | | | | | | |
sys | to_char | text | double precision | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | dsinterval, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | orainterval_to_char | format dsi
nterval to text
sys | to_char | text | integer | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | money | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | num numeric | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | real | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | smallint | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select cast($1 as text);+|
| | | | | | | | | | | |
sys | to_char | text | text | 函数 | 不可更改 | 安全的 | system | 调用者 | | c | to_datum |
sys | to_char | text | text, text | 函数 | 不可更改 | 安全的 | system | 调用者 | | c | text_with_format_to_char |
sys | to_char | text | timestamp without time zone | 函数 | 不可更改 | 安全的 | system | 调用者 | | c | ora_to_char_timestamp | Convert ti
mestamp to string
sys | to_char | text | yminterval, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | orainterval_to_char | format ymi
nterval to text
(25 行记录)
--查看索引中表的数据类型
xjtopicis=# \d "public"."reg_licenseissueinfo"
数据表 "public.reg_licenseissueinfo"
栏位 | 类型 | 校对规则 | 可空的 | 预设
--------------+--------------------------------+----------+----------+--------------
id | numeric(19,0) | | not null |
marprid | numeric(19,0) | | not null |
liccode | character varying(9 char) | | |
licname | character varying(200 char) | | |
regorgcode | character varying(9 char) | | |
regorg | character varying(100 char) | | |
regdate | date | | |
createorg | character varying(100 char) | | |
timestamp | date | | |
batch | character varying(1 char) | | not null | '1'::varchar
exctimestamp | timestamp(6) without time zone | | |
索引:
"index_licenseissueinfo_liccode_a6c008ba" btree (liccode)
"reg_licissinfo_marprid_b5488911" btree (marprid)
--修改对应函数为immutable
xjtopicis=# alter function to_char(timestamp(6) without time zone,text) immutable;
ALTER FUNCTION
--再次执行sql成功
报错的sql_2的解决办法
--查看函数类型
xjtopicis=# \df+ TO_NUMBER 函数列表
架构模式 | 名称 | 结果数据类型 | 参数数据类型 | 类型 | 挥发性 | 平行 | 拥有者 | 安全 | 存取权限 | 程序语言 | 原始程式
| 描述
------------+-----------+--------------+--------------+------+--------+----------+--------+--------+----------+----------+------------------------------------------------------------
---------------------------------------------+-------------------------
pg_catalog | to_number | numeric | text, text | 函数 | 稳定 | 安全的 | system | 调用者 | | internal | numeric_to_number
| convert text to numeric
sys | to_number | numeric | text | 函数 | 稳定 | 不安全的 | system | 调用者 | | sql | select to_number($1, '999999999999999999999999999999999999
99D99999999999999999999999999999999999999');+|
| | | | | | | | | | |
|
(2 行记录)
--查看索引中表的数据类型
xjtopicis=# \d "public"."ecps_baseinfo_2013"
数据表 "public.ecps_baseinfo_2013"
栏位 | 类型 | 校对规则 | 可空的 | 预设
-----------------------+--------------------------------+----------+----------+-------------
ancheid | character varying(50 char) | | not null |
pripid | character varying(36 char) | | not null |
anchedate | timestamp(6) without time zone | | |
ancheyear | character varying(8 char) | | not null |
regno | character varying(50 char) | | |
uniscid | character varying(50 char) | | |
entname | character varying(200 char) | | |
enttype | character varying(64 char) | | |
lastupdatetime | timestamp(6) without time zone | | not null |
createtime | timestamp(6) without time zone | | not null |
entclassify | character varying(2 char) | | |
annrepform | character varying(2 char) | | |
state | character varying(2 char) | | |
sourcetype | character varying(2 char) | | |
pubstate | character varying(2 char) | | |
userid | character varying(50 char) | | |
tel | character varying(500 char) | | |
addr | character varying(512 char) | | |
postalcode | character varying(12 char) | | |
email | character varying(100 char) | | |
busst | character varying(2 char) | | |
busst_cn | character varying(18 char) | | |
empnum | numeric(12,0) | | |
empnumdis | character varying(2 char) | | |
antype | character varying(6 char) | | |
colgranum | numeric(12,0) | | |
colemplnum | numeric(12,0) | | |
retsolnum | numeric(12,0) | | |
retemplnum | numeric(12,0) | | |
dispernum | numeric(12,0) | | |
disemplnum | numeric(12,0) | | |
unenum | numeric(12,0) | | |
uneemplnum | numeric(12,0) | | |
dependententname | character varying(100 char) | | |
assgro | numeric(24,6) | | |
assgrodis | character varying(2 char) | | |
liagro | numeric(24,6) | | |
liagrodis | character varying(2 char) | | |
vendinc | numeric(24,6) | | |
vendincdis | character varying(2 char) | | |
maibusinc | numeric(24,6) | | |
maibusincdis | character varying(2 char) | | |
progro | numeric(24,6) | | |
progrodis | character varying(2 char) | | |
netinc | numeric(24,6) | | |
netincdis | character varying(2 char) | | |
ratgro | numeric(24,6) | | |
ratgrodis | character varying(2 char) | | |
totequ | numeric(24,6) | | |
totequdis | character varying(2 char) | | |
numparm | numeric(12,0) | | |
parins | character varying(2 char) | | |
parins_cn | character varying(16 char) | | |
resparmsign | character varying(2 char) | | |
resparsecsign | character varying(2 char) | | |
standardesflag | character varying(2 char) | | |
newnumaff | numeric(12,0) | | |
newnumparm | numeric(12,0) | | |
partyorgtype | character varying(2 char) | | |
partyorgenterprisenum | numeric(12,0) | | |
farspeartname | character varying(200 char) | | |
memnum | numeric(12,0) | | |
farnum | numeric(6,0) | | |
annnewmemnum | numeric(6,0) | | |
annredmemnum | numeric(6,0) | | |
priyeasales | numeric(24,6) | | |
priyeasalesdis | character varying(2 char) | | |
priyeaprofit | numeric(24,6) | | |
priyeaprofitdis | character varying(2 char) | | |
priyeasub | numeric(24,6) | | |
priyeasubdis | character varying(2 char) | | |
priyealoan | numeric(24,6) | | |
priyealoandis | character varying(2 char) | | |
name | character varying(500 char) | | |
traname | character varying(200 char) | | |
fundam | numeric(24,6) | | |
encryptionmessage | character varying(2000 char) | | |
akbean | character varying(500 char) | | |
busstsign | character varying(2 char) | | |
websitsign | character varying(2 char) | | |
guaranteesign | character varying(2 char) | | |
forinvestsign | character varying(2 char) | | |
stocktransign | character varying(2 char) | | |
lasttab | character varying(2 char) | | |
partybuilding | character varying(2 char) | | |
receipttimestamp | timestamp(6) without time zone | | | "sysdate"()
索引:
"idx_ecps_baseinfo_2013_pripid_be3e14ea" btree (pripid)
"idx_ecps_baseinfo_2013_userid_1bc5432e" btree (userid)
"idx_ecps_baseinfo_2013_year_c0cef371" btree (ancheyear)
--修改对应函数为immutable
xjtopicis=# alter function to_number(text,text) immutable;
ALTER FUNCTION
--再次执行sql成功
CREATE INDEX "idx_ecps_baseinfo_2013_numyear_4ecdbdd9" ON "public"."ecps_baseinfo_2013" ((TO_NUMBER("ANCHEYEAR")) ASC);参考链接:https://blog.csdn.net/Yusili1111/article/details/127328553
ERROR: 对访问方法 "btree" 数据类型 unknown 没有默认的操作符表
查看错误日志
com.kingbase8.util.KSQLException: ERROR: 对访问方法 "btree" 数据类型 unknown 没有默认的操作符表
Hint: 你必须指定一个操作符表给索引或定义一个默认的操作符表给数据类型.错误的sql:
CREATE INDEX "idx_enthis_marprid_93a6ff32" ON "public"."reg_enthistinfoxml" (('MARPRID') ASC);解决办法
将MARPRID前后的单引号去掉或者将单引号换成双引号,再次执行成功。个人理解为金仓中字段要么不用双引号括起来要么就用双引号括起来不能用单引号括起来,MySQL中才用单引号将字段括起来,而文档的金仓数据库兼容模式是Oracle
CREATE INDEX "idx_enthis_marprid_93a6ff32" ON "public"."reg_enthistinfoxml" ((MARPRID) ASC);



