Oracle数据库迁移PostgreSQL数据库问题及解决



目录

  • 如何计划迁移数据库(现状及问题分析)
  • 统计系统表及表功能
  • 解耦公共表
  • 建立数据库
  • 迁移表结构
  • 导入表数据
  • 改SQL语法
  • 保证数据时效性和完整性
  • 其他(优化SQL等)



1.如何计划迁移数据库


将数据库从Oracle迁移至PostgreSQL数据库,需要考虑的有很多。

但是有一点是不变的,或者说是目的:要保证数据库迁移后,系统功能能够正常使用,或对业务逻辑尽可能少的修改(修改业务逻辑可能会出现意想不到的连锁问题)

那么,就需要想办法将原有的Oracle数据库整体结构,尽可能的在PostgreSQL上还原,这样才能保证不必大量调整业务逻辑。





明确目的之后,可以具体分析系统现状了:

该系统所使用的是Oracle数据库,但Orale数据库是一个总库,其他系统使用的表也在该库中,使用属主区分表。所以该系统除了自身使用的表之外,还使用了一部分公共表。

这样一来,在迁移数据库之前,除了统计系统本身的表外,还要进行公共表解耦

其次,如果要迁移到PostgreSQL数据库,那么建表语句就必须按照PostgreSQL的语法写,即调整建表脚本

除了建表脚本,原Oracle数据库还有大量的序列、索引、存储过程等,这些也需要移植过去

然后就是导入原有的表数据,进行本地系统功能的SQL语句调整。

最后需要解决的,就是在生产环境切换数据库,那么如何保证数据的完整性和时效性?





总结以上的问题要点:

1.迁移数据库之前,统计系统本身的表清单和表功能清单等;

2.迁移数据库之前,进行公共表解耦;

3.调整建表脚本;

4.移植序列、索引、存储过程等;

5.导入原有的表数据;

6.调整系统原本的SQL语句;

7.生产环境保证数据的完整性和时效性;

8.其他问题及解决;




2.统计系统表及表功能


统计系统的使用的表和表功能,主要是为了明确需要迁移的表,以及表所负责的功能(方便数据迁移时,确定数据导入的先后顺序)

这一步很简单,但是比较耗费时间,需要耐心和细心

最好能够一起统计表使用到的序列和索引等,方便之后的迁移操作。

3.解耦公共表


之所以需要解耦公共表,原因有二:

1.如果把使用到的公共表(表属主并不是该迁移的系统)迁移到PostgreSQL数据库,那么其他使用该表的系统就无法正常使用

2.公司规定,不是自己系统的表,一般是只进行读操作,不会进行写入或修改操作,更不会迁移其他系统的表;





根据以上原因,最终采用的方案是:

由表属主的系统,提供给我们这个迁移系统所需要的接口,我们由原来的直接查询其他系统的表,转为调用其他系统提供的接口来查询需要的数据;

这么做的好处就是,将原来的公共表与本系统进行解耦,同时当该系统进行数据库迁移后(其他系统仍是Oracle数据库),还能够查询到需要的数据,不会影响其他系统运行。





需要注意的是:

在进行表解耦之前,需要先统计该系统使用的外部表,包括本系统使用外部表的哪些关联字段、外部表在本系统中的作用等信息。

然后根据这些信息,与其他系统负责人沟通并开发接口、联调接口等。




4.建立数据库


在各环境的数据库正式迁移之前,可以先在本地的PostgreSQL数据库,建立一个新的系统数据库用于本地系统功能和业务测试。

当本地测试的差不多了,就可以把脚本提供给DBA,交由DBA去创建各环境的PostgreSQL数据库。

至于怎么在本地安装PostgreSQL数据库,这里就不赘述了。





5.迁移表结构(包括序列、索引等)


迁移表结构涉及的东西比较多,可以参考以下的迁移步骤:

1.编写新的CREATE TABLE脚本(按照PostgreSQL的语法);

2.编写新的INDEX、SEQUENCE等脚本(索引、序列的各种名称、参数都和Oracle的一致,尽量只调整语法差异)

5.1 CREATE TABLE脚本

编写CREATE TABLE脚本的时候,除了需要注意建表的语法之外,还有Oracle和PostgreSQL两种数据库不同字段类型的替换。


例如:


varchar类型和character varying类型

Oracle中,定长的char类型最大长度是2000,变长的varchar类型长度最大是2000、varchar2类型最大长度是4000。

字段类型 长度是否可变 最大长度 补充
char 2000 存储长度为指定的长度,即char(20)存'abc',占20字节;比varchar占空间多,但效率稍高;
varchar 2000 存储长度为实际长度,即varchar(20)存'abc',占3字节;比char省空间,但效率稍低;存中文2字节,英文1字节;对空串不处理;
varchar2 4000 Oracle特有,存储特点和varchar一致,但varchar2存中英文都是2字节;最大长度限制为varcahr的2倍;会将空串处理为null;

PostgreSQL中,定长的char类型和变长的varchar类型的最大长度都是1G(10485760),变长的text类型则没有长度限制。

字段类型 长度是否可变 最大长度 补充
text 无限制 性能和varchar几乎相同,但存储结构不同;
character,char 1G(10485760) 定长;默认长度为1G;不足部分会补空白;
character varying,varchar 1G(10485760) 变长;默认长度为1;占用字节为实际存储长度;

在PostgreSQL中,text、char和varcahr的性能是没有区别的,大多数情况下使用text和varchar比较好;

character是全称,char是别名(简称);character varying是全称,varchar是别名(简称);
Oracle中较长的字段,可以用PostgreSQL中的character varying替代,长度是没问题的




number类型和numeric类型

Oracle中,使用number类型来保存对精度要求高的数值,比如货币、金额等

对精度要求不高或没有要求的尽量不要用numeric类型,因为它的效率很低

字段类型 范围 说明 例子
number(precision,scale) percision:1到38;scale:-78到124 不指定percision,默认为38; number(8,3)

PostgreSQL中,与number类型对应的是numeric类型

字段类型 范围 说明 例子
numeric(precision,scale) percision:最大131072个数字;scale:最大16383个数字 变量;percision为总精度,scale为小数位位数;
若小数位超过指定位数,则进行四舍五入;
两参数同时省略时,可存任何不超上限精度的数字;
可存特殊值NaN(NaN与任何值都不等,包括自身);
numeric(8,3)
decimal(precision,scale) 同上 同上(只是语法支持,因为其底层就是numeric类型) decimal(8,3)或decimal(8,-2)



date类型和timestamp类型

Oracle中,使用date类型来保存时间数据,如创建时间、修改时间等

字段类型 格式 说明
date 标准:DD-MON-YY 存储的时间格式可定义,如“yyyy-mm-dd”或“yyyy-mm-dd hh24:mi:ss”

PostgreSQL中,与date类型对应的是timestamp类型

字段类型 格式 说明
timestamp 存时间日期
time 存时间
date 存日期
timestampz 存timestamp和时区
interval 存一段时间

其他数据类型不再一一介绍,可以通过查阅PostgreSQl轻松学来获取相关知识。

建表语句例子:

-- 删减了一部分关键字段,只保留了基本的字段,同表一起创建的还有该表使用的索引
CREATE TABLE cp_opr.user_role
(
id varchar(20) COLLATE pg."default" NOT NULL,
role_id varchar(50) COLLATE pg."default" NOT NULL,
department_chinese_name varchar(255) COLLATE pg."default" NOT NULL,
user_name varchar(30) COLLATE pg."default" NOT NULL,
department_code varchar(30) COLLATE pg."default",
user_id varchar(30) COLLATE pg."default" NOT NULL,
state varchar(2) COLLATE pg."default" NOT NULL,
flag varchar(2) COLLATE pg."default" DEFAULT '1'::varchar,
manager varchar(30) COLLATE pg."default",
create_by varchar(100) COLLATE pg."default" DEFAULT 'complaint'::varchar,
create_date timestamp(0) without time zone NOT NULL DEFAULT now(),
update_by varchar(100) COLLATE pg."default",
update_date timestamp(0) without time zone,
CONSTRAINT user_role PRIMARY KEY (id)
); COMMENT ON TABLE cp_opr.user_role
IS '用户角色表'; COMMENT ON COLUMN cp_opr.user_role.id
IS 'ID'; COMMENT ON COLUMN cp_opr.user_role.role_id
IS '角色ID'; COMMENT ON COLUMN cp_opr.user_role.department_chinese_name
IS '机构名称'; COMMENT ON COLUMN cp_opr.user_role.user_name
IS '用户名称'; COMMENT ON COLUMN cp_opr.user_role.department_code
IS '机构'; COMMENT ON COLUMN cp_opr.user_role.user_id
IS '用户ID'; COMMENT ON COLUMN cp_opr.user_role.state
IS '状态'; COMMENT ON COLUMN cp_opr.user_role.flag
IS '有效标志'; COMMENT ON COLUMN cp_opr.user_role.manager
IS '角色的管理员'; COMMENT ON COLUMN cp_opr.user_role.create_by
IS '创建人'; COMMENT ON COLUMN cp_opr.user_role.create_date
IS '创建日期'; COMMENT ON COLUMN cp_opr.user_role.update_by
IS '修改人'; COMMENT ON COLUMN cp_opr.user_role.update_date
IS '修改日期'; -- 不能创建与表同名的索引
-- CREATE INDEX
CREATE INDEX index_role_dep_code ON cp_opr.user_role USING btree(department_code) ;
CREATE INDEX index_role_id ON cp_opr.user_role USING btree(role_id) ;
CREATE INDEX index_role_user_id ON cp_opr.user_role USING btree(user_id) ;

5.2 移植SEQUENCE序列

Oracle和PostgreSQl的序列创建方法大致上一样,但是会有一些细微的差别。


需要注意的是,新的序列在创建的时候,高速缓存值最好和原序列的一致

否则可能会发生序列跳跃(Oracle的最低可为0,PostgreSQl的最低为1)。

-- 以下是三个序列的创建语句,当前设置的初始值为1,当迁移后需要查询原序列的当前值,并修改现在的初始值1
-- CREATE SEQUENCE
create sequence cp_opr.sq_tauditdetail_id
minvalue 1
maxvalue 9223372036854775807
start with 1
increment by 1
cache 10; -- CREATE SEQUENCE
create sequence cp_opr.seq_complaint_email_log_id
minvalue 1
maxvalue 9223372036854775807
start with 1
increment by 1
cache 10; -- CREATE SEQUENCE
create sequence cp_opr.seq_t_complaint_mobilesms_log
minvalue 1
maxvalue 9223372036854775807
start with 1
increment by 1
cache 10;

6.导入原有的表数据


导入Oracle数据库的历史数据,我们采用的方案是写批处理,然后跑批导数据

因为是本地和sit环境,所以数据量大的表可以适当删掉些无用的旧数据,以提升导入速度,方便测试,这里就不上批处理的代码了。



导入数据的时候,需要注意

数据导入的先后顺序,因为有的表数据通过逻辑外键关联,这些逻辑外键不允许为空。如果顺序乱了,则可能导入数据的时候报错



7.改SQL语法


这一步主要改的是系统中的SQL语句,因为PostgreSQl的语法和Oracle的差异还是不小的,所以必须要进行调整。

调整的内容可以分为2部分:

1.SQL语法();

2.SQL函数;

7.1 SQL语法

语法需要注意的地方,主要是字段类型的转换,这是因为PostgreSQL的语法要求的。


字段类型的指定(转换)需要用“::”符号,例如:

-- 不仅可以指定WHERE条件中的子类类型,还可以指定SELECT查询字段的类型
SELECT T.BRANCH_ID::VARCHAR
FROM T_xxx T
WHERE T.BRANCH_ID <> 1 ]]>
AND T.PARENT_ID = 1
AND T.BRANCH_ID::VARCHAR
<iterate prepend="in" conjunction="," open="(" close=")">
#deplist[]#
</iterate> -- INSERT语句用的最为频繁
INSERT INTO T_C_C
(CREATED_BY,
CREATED_DATE,
UPDATED_BY,
UPDATED_DATE,
CALENDAR_ID,
CALENDAR_DATE,
IS_WORKING_DATE,
YEAR,
MONTH,
DAY,
QUARTER,
WEEK)
VALUES(#createdBy:VARCHAR#,
now(),
#updatedBy:VARCHAR#,
now(),
#calendarId:VARCHAR#,
#calendarDate#::timestamp,
#isWorkingDate:VARCHAR#,
substr(to_char(#calendarDate#::timestamp,'YYYYQMMDD'),1,4),
substr(to_char(#calendarDate#::timestamp,'YYYYQMMDD'),6,2),
substr(to_char(#calendarDate#::timestamp,'YYYYQMMDD'),8,2),
substr(to_char(#calendarDate#::timestamp,'YYYYQMMDD'),5,1),
to_char(#calendarDate#::timestamp,'ww')); -- UPDATE语句中,不能够使用表别名 -- 特殊的时间加减法运算
select CURRENT_TIMESTAMP::TIMESTAMP + INTERVAL '5 day'; -- 分页查询语法
SELECT * FROM T_xxx LIMIT 20 OFFSET 0; -- 左右连接查询 需要使用LEFT OUTER JOIN 或 RIGHT OUTER JOIN
SELECT * FROM T_A a LEFT OUTER JOIN T_B b WHERE a.id=b.id; -- 子查询必须要有别名
SELECT a.id,a.name,a.phone FROM(SELECT * FROM T_XXX WHERE ID in('1','2','5'))a; -- 插入空值NULL的时候,必须明确指定为NULL,而不能和Oracle一样是''

7.2 SQL函数

以下列举一部分,更多的函数可以自行百度

Oracle函数 PostgreSQL函数
Decode case xxx when
Nvl Coalesce
Instr Strops
Nlssort convert_to
Trunc date_trunc

8.保证数据时效性和完整性


8.1 数据完整性


数据的完整性,主要依靠的是:

1.一开始系统使用表统计,是否统计的足够完整;

2.导入数据的时候顺序;



测试导入后的数据是否完整也比较简单:

1.观察数据导入时是否有日志异常;

2.将业务从头到尾走一遍,看看数据是否查不到或者流程走不通;

8.2 数据时效性


这个主要涉及的是,当生产环境数据库由Oracle切换到PostgreSQL的时候,需要一定的时间去导入原有的数据。

那么导入数据的这段时间中,产生的新数据该如何导入新数据库?

如果直接导入,会不会与原有的数据关联不上?除此之外,还会有什么意想不到的问题?



比较遗憾的是,因为本次迁移的系统属于比较边缘的系统,所以最终采用的方案是

生产数据库切换的时候,将服务器关闭一段时间,阻止新数据的产生,直到旧数据迁移完毕再重启服务器。



除了本次迁移的系统,还有很多系统也需要迁移,如果那些系统迁移的时候遇到了这个问题,并有了更好的方案,再来更新。

9.其他


暂无,如果发现了再来补充~

Oracle数据库迁移至PostgreSQL数据库问题及解决的更多相关文章

  1. 将ACCESS数据库迁移到SQLSERVER数据库

    原文:将ACCESS数据库迁移到SQLSERVER数据库 将ACCESS数据库迁移到SQLSERVER数据库 ACCESS2000文件 用ACCESS2007打开,并迁移到SQLSERVER2005里 ...

  2. 将Oracle数据库迁移到达梦数据库

    公司某产品在项目现场上常用到的数据库有Oracle和达梦. 做性能测试需要根据项目现场预埋大量的基础数据和业务数据,耗费时间.精力.故完成Oracle数据库的性能测试之后,采用直接将Oracle数据库 ...

  3. ubuntu系统lamp环境搭建、数据库迁移、设置数据库外部访问

    sudo passwd root设置两次密码su输入设置的密码exit (退出root帐号) 1.sudo apt-get update 2.sudo apt-get install apache2 ...

  4. MySQL数据库迁移与MySQL数据库批量恢复

    目录 一.MySQL数据库迁移或备份 1. 了解使用InnoDB引擎创建数据库所产生的文件 2. 迁移数据库步骤 1. 从A服务器迁移至B服务器 2. MySQL重装并导入之前数据库 二.MySQL数 ...

  5. Oracle迁移至PostgreSQL工具之Ora2Pg

    1. 描述 Ora2Pg是一个免费的工具,用于将Oracle数据库迁移到PostgreSQL兼容的模式.它连接您的Oracle数据库,自动扫描并提取它的结构或数据,然后生成可以装载到PostgreSQ ...

  6. .net工作流引擎ccflow新增支持PostgreSQL数据库的功能的发布说明

    关键字: 驰骋工作流程快速开发平台 工作流程管理系统 工作流引擎 asp.net工作流引擎  java工作流引擎. 各位驰骋工作流引擎爱好着,经过驰骋公司与正元公司的共同努力,ccflow支持Post ...

  7. ABP Migration(数据库迁移)

    今天准备说说EntityFramework 6.0+,它与我之前所学的4.0有所区别,自从4.1发布以来,code first 被许多人所钟爱,Dbcontext API也由此时而生.早在学校的时候就 ...

  8. 在ASP.NET MVC5 及 Visual Studio 2013 中为Identity账户系统配置数据库链接及Code-First数据库迁移

    在ASP.NET MVC5 及 Visual Studio 2013 中为Identity账户系统配置数据库链接及Code-First数据库迁移 最近发布的ASP.NET MVC 5 及Visual ...

  9. postGreSQL数据库部署及简单使用

    1,deployByRuiyIns rpm -ivh http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-centos94-9.4-1.no ...

随机推荐

  1. 洛谷 P4408 [NOI2003]逃学的小孩

    题目传送门 题目描述 Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:“喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?”一听说要考试,Chris的父母就心急如焚, ...

  2. 武科WUST-CTF2020“Tiki组 ”

    赛事信息 官网地址:https://ctfgame.w-ais.cn/参赛地址:https://ctfgame.w-ais.cn/起止时间:2020-03-27 18:00:00 - 2020-03- ...

  3. show me bug

    比较版本号 前者大返回1 后者大返回-1 两者一样大返回0 #include <iostream> #include<string> using namespace std; ...

  4. Makeflie学习笔记

    makefile基本格式 TARGER... : DEPENDEDS... COMMAND ... ... TARGET:规则定义的目标.生成的目标文件的文件名或者是一个动作 DEPENDEDS:执行 ...

  5. 上海python14期第一次周考

    上海python14期第一次周考 1 介绍 满分50分 考试范围: Python语法 数据类型 流程控制 考试时间: 周五下午3.00点-晚6:00 2 基础题(38分) 什么是编程语言?什么是语言? ...

  6. ReadWriteLock锁的应用

    对于 Lock 锁来说,如果要实现 "一写多读" 的并发状态(即允许同时读,不允许同时写),需要对 "写操作" 加锁,对 "读操作" 不作要 ...

  7. EM算法理论与推导

    EM算法(Expectation-maximization),又称最大期望算法,是一种迭代算法,用于含有隐变量的概率模型参数的极大似然估计(或极大后验概率估计) 从定义可知,该算法是用来估计参数的,这 ...

  8. 数据可视化之分析篇(十)Power BI应用:如何计算在职员工数量?

    ​https://zhuanlan.zhihu.com/p/128652582 经常碰到的一类问题是,如何根据起止日期来计算某个时间点的数量,比如: 已知合同的生效日期和到期日期,特定日期的有效合同有 ...

  9. JavaScript之setinterval的具体使用

    关于setInterval在api文档中也有很详细的解释,比如下面那两个: setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式. setInterval() 方法会不停 ...

  10. 用前端姿势玩docker【二】dockerfile定制镜像初体验

    前言 书接上文,关于dockerfile指令的api在此处不做赘述,在此只是记录下注意事项: '示坑以埋之'. 配置指令 FROM dockerfile必须以此开头 一个dockerfile可执行添加 ...