暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

mysql到postgresql 异构数据迁移改造方案

4228

本次mysql到postgresql数据库迁移工具使用pgloader迁移,做常规迁移。如果遇到特殊字段,比如mysql中的地理坐标字段gemotry,需要采用其他方法。该方法在具体说明。


 安装条件准备

 

pgloader版本

pgloader-bundle-3.6.2.tgz

Pgloader 部署的服务器ip地址

192.168.56.112(请根据实际环境部署该软件,保证该地址可以同时连接pg和mysql数据库)

源端mysql数据库地址

192.168.56.113

目标端postgres 数据库地址

192.168.56.114

Pgloader 安装部署

源端mysql数据库参数要求

Innodb_large_prefix=on

net_write_timeout=3600;

net_read_timeout=3600;

其中net_write_timeout/net_read_timeout在迁移期间建议修改,迁移后恢复成默认值

目标端Postgres 数据库要求

在mysql rds中是通过geometory字段类型存储经纬度等地理位置信息,在通过pgloader 转换后,默认会转换成point类型,如果需要改变为geometory字段类型,需要安装gis插件。

数据库迁移账号

数据库迁移账号请避免带有特殊字符,比如@#¥%^&等,如有特殊字符@,可以先进行密码修改,迁移完成后,在修改回去或者需要多加一个@,即密码如果遇到@,则再需要再后面添加一个@

PGLoader工具安装

 安装依赖包

以下的安装操作都是以root用户执行。

 

yum -y install yum-utils rpmdevtools @"Development Tools"  sqlite-devel zlib-devel

yum -y install epel-release

yum -y install sbcl

yum install freetds freetds-devel -y

yum -y install  unixODBC

yum -y install  libtool-ltdl*

 

yum -y install  cl-asdf-20101028-8.el7.noarch.rpm

yum -y install  common-lisp-controller-7.4-8.el7.noarch.rpm

yum -y install  sbcl-1.4.0-1.el7.x86_64.rpm

 

rpm -ivh freetds-libs-1.1.20-1.el7.x86_64.rpm  freetds-1.1.20-1.el7.x86_64.rpm

 

yum -y install  freetds-devel-1.1.20-1.el7.x86_64.rpm

 

ln -s /usr/lib64/libsybdb.so.5 /usr/lib64/libsybdb.so

 

Pgloader解压安装

软件安装包目录为/root/pgloader_soft,现场可以根据实际环境自行决定上传目录。

tar -xvf pgloader-bundle-3.6.2.tgz

cd pgloader-bundle-3.6.2/

make pgloader

--出现下面的信息表示安装成功

;; loading system "cffi"

;; loading system "cl+ssl"

;; loading system "mssql"

;; loading file #P"/root/pgloader_soft/pgloader-bundle-3.6.2/local-projects/pgloader-3.6.2/src/hooks.lisp"

;; loading system "pgloader"

compressed 0 bytes into 8 at level -1

compressed 32768 bytes into 617 at level -1

compressed 3047424 bytes into 820965 at level -1

compressed 23691264 bytes into 6785671 at level -1

compressed 91127808 bytes into 16513612 at level -1

# that's ugly, but necessary when building on Windows :(

mv bin/pgloader.tmp bin/pgloader

 

 设置alias

vi /etc/profile

 

alias pgloader=/root/pgloader_soft/pgloader-bundle-3.6.2/bin/pgloader

:wq

 

source /etc/profile

 

 验证安装

[root@orcl bin]# pgloader --version;

pgloader version "3.6.2"

compiled with SBCL 1.4.0-1.el7


 源端数据库对象收集

在迁移前需要对源数据库的对象和数据进行一次整理,以便后续的数据对象和数据验证

对象验证

Mysql对象验证包括:表,视图,存储过程,触发器,函数等。

 

查看表数量

本脚统计的是电网资源实例下的所有表对象的数量。如果是其他实例,请输入对应的schema

SELECT

count(*),

table_schema

FROM

information_schema.`TABLES` d

WHERE

d.table_schema IN (

'xxxxx')

AND d.table_type = 'BASE TABLE'

group by table_schema

order by table_schema

 

查看视图数量

本脚统计的是电网资源实例下的所有视图对象的数量。如果是其他实例,请输入对应的schema

select count(*),

table_schema  

from information_schema.VIEWS d WHERE

d.table_schema IN (

'xxxxxx',

)

group by table_schema

order by table_schema

 

查看存储过程,函数,序列数量

本脚统计的是电网资源实例下的所有存储过程,函数对象的数量。如果是其他实例,请输入对应的schema

SELECT

count(*),

routine_type,

routine_schema

FROM

information_schema.ROUTINES d

WHERE

d.routine_schema IN ( 'xxxxxx' )

GROUP BY

routine_type,

routine_schema

ORDER BY

routine_schema,

routine_type

 

查看触发器数量

本脚统计的是电网资源实例下的所有触发器对象的数量。如果是其他实例,请输入对应的schema

SELECT

count(*),

trigger_schema

FROM

information_schema.`TRIGGERS` d

WHERE

d.trigger_schema IN ( 'xxxxxx' )

GROUP BY

trigger_schema

ORDER BY

trigger_schema

特性验证

不同数据库之间的迁移,可能伴随着特性的转变。Mysql中需要关注自增和自动更新时间两个特性,其中自增特性在postgresql数据库中是通过序列实现,自动更新时间特性在postgresql数据库中是通过触发器实现。

 

查看自增特性和自动更新特性

SELECT

count(*),

table_schema,

extra

FROM

information_schema.`COLUMNS` d

WHERE

( d.extra LIKE 'auto%' OR d.extra LIKE 'on%' )

GROUP BY

table_schema,

extra

order by table_schema,extra


数据验证

验证每个表的数据量

参考脚本:<mysql获得指定schema下表的精确行数.sql>



目标端创建数据库


数据迁移配置

常规数据迁移

常规数据迁移

test1迁移配置和迁移

请注意新建pg.load.test1 配置文件。以下配置文件都使用相同方法。

配置文件请修改为实际的数据库链接地址。

 test1 在mysql中是database的概念,迁移到postgresql数据库中会变成schema 


该配置文件为:把mysql中test1数据库,迁移到pg中的tdb数据库下,

vi pg.load.test1

 

load database

from mysql://admin_user:admin_user@192.168.56.113:3306/test1

into pgsql://admin_user:admin_user@192.168.56.114:5432/tdb;

 执行

pgloader --verbose pg.load.test1>> pg.load.test1 2>&1

特殊字段迁移geometry


在迁移过程中需要注意到特殊字段,在阿里云mysql rds中是通过geometory字段类型存储经纬度等地理位置信息,在通过pgloader 转换后,默认会转换成point类型,如果需要改变为geometory字段类型,该字段类型需要手动修改

以下脚本都在postgresql数据库tdb中执行

select 'ALTER TABLE test1.'||a.table_name||' ALTER COLUMN geometry TYPE public.geometry USING geometry::public.geometry;' from information_schema.columns a where a.table_schema='test1'  and a.column_name='geometry' and   a.data_type='point'

3: 特殊字段数据迁移

由于geo字段类型是非标准常见的字段类型,需要专门的开发工具进行迁移。迁移工具为

nrxt-gis-geotransfer,参考附件工具。该工具需要jdk8环境

 

配置数据源

 #服务端口

server:

  port: 18009

  #context-path: /psr-platform-transfer

  

spring:

  application:

    name: psr-platform-transfer

  datasource:

    druid:

      target:

##目标端数据库

        type: com.alibaba.druid.pool.DruidDataSource

        driverClassName: org.postgresql.Driver

        url: jdbc:postgresql://192.168.56.114:5432/tdb?currentSchema=test1

        username: admin_user

        password: admin_user

        initialSize: 10

        maxActive: 100

      source:

##源端数据库

        type: com.alibaba.druid.pool.DruidDataSource

        driverClassName: com.mysql.cj.jdbc.Driver

        url: jdbc:mysql://192.168.56.113:3306/test?autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8&allowMultiQueries=true

        username: admin_user

        password: admin_user

        initialSize: 10

        maxActive: 100

        

#----------- 日志配置 -----------

logging:

  level:

    root: INFO     #设置root日志的级别,一般为INFO (日志级别:TRACE < DEBUG < INFO < WARN < ERROR < FATAL),建议为INFO

    com.sgcc.nrxt.pms.repositories: INFO

 

开始执行

建议window下执行

windows双击start.bat启动

Linux 命令行启动 nohup ./start.sh start


触发器对象处理

在迁移的过程中出现大量的触发器,该触发器是有mysql中的ON UPDATE CURRENT_TIMESTAMP 功能,在经过pgloader 迁移改造成postgres后,会变成触发器。



由于实际开发环境中要求不能有触发器,所有的触发器功能由应用程序端进行实现,因此需要删除该类触发器。具体操作如下:
 

 

单个触发器删除示例脚本:

drop trigger on_update_current_timestamp on xxx.t_xxx_xxx;

批量触发器删除示例脚本:

 

生成批量删除触发器对象脚本:

select 'drop trigger '||t.trigger_name||' on '||t.event_object_schema||'.'||t.event_object_table||';' from information_schema.triggers t ;

 

生成批量删除触发器函数脚本:

 

SELECT FORMAT('DROP FUNCTION %s(%s);'

             ,p.oid::regproc

             ,pg_get_function_identity_arguments(p.oid))

FROM pg_proc AS p

INNER JOIN pg_namespace AS n

ON p.pronamespace = n.oid

WHERE n.nspname NOT IN ('pg_catalog', 'information_schema', 'public');

 


时区时间字段处理

在mysql中 timestamp字段会自动映射成timestamptz,该字段值带有时区,需要改成非时区的字段类型。

请注意修改字段期间会产生大量的归档日志,请及时清理,表的数据量越大,修改字段越慢,可以同时开启多个sql窗口运行

SELECT

'alter table '||d.table_schema||'.'||table_name||' alter column '||d.column_name||' TYPE timestamp(6) USING  ' ||d.column_name||'::timestamp(6);'

FROM

information_schema.COLUMNS d

WHERE

d.data_type LIKE'timestamp with time zone'

AND d.table_schema NOT IN ( 'public', 'information_schema', 'pg_catalog' )

Order by table_schema ,table_name

date时间字段处理

在mysql中 date字段会自动映射成date,从业务中了解到该字段类型date不适配引用代码,需要修改为timestamp(6)。

请注意修改字段期间会产生大量的归档日志,请及时清理,表的数据量越大,修改字段越慢,可以同时开启多个sql窗口运行

SELECT

'alter table '||d.table_schema||'.'||table_name||' alter column '||d.column_name||' TYPE timestamp(6) USING  ' ||d.column_name||'::timestamp(6);'

FROM

information_schema.COLUMNS d

WHERE

d.data_type LIKE 'date'

AND d.table_schema NOT IN ( 'public', 'information_schema', 'pg_catalog' )

Order by table_schema ,table_name


迁移错误处理

非空约束错误处理

在迁移过程中出现表 t_xxx 迁移错误,错误原因是由于非空约束问题。

ERROR Database error 23502: null value in column "lock_time" violates not-null constraint

DETAIL: Failing row contains (1305343082518937601, jgZ, dcdb9e4d-a85f-4013-80df-4e2fa43f5a3c, null, 1304434587946971138, 7dae530a4640288285747d757c01747dae50f80422, eeee, 273786, null, null, null, null, null, null, null).

CONTEXT: COPY t_xxx , line 1: "1305343082518937601 jgZ dcdb9e4d-a85f-4013-80df-4e2fa43f5a3c \N 1304434587946971138 7dae530a46402882..."

 

需要手工处理,针对此问题,在进行表数据导出。

单表迁移配置

 

vi pg.load.txx

 

load database

from mysql://admin_user:admin_user@192.168.56.113:3306/test1

into pgsql://admin_user:admin_user@192.168.56.114:5432/tdb;

  INCLUDING ONLY TABLE NAMES MATCHING ' t_xx';

 

pgloader pg.load.txx

 

默认值错误处理

在mysql 迁移postgres 过程中,由于默认值格式错误导致表,无法迁移成功。需要手动修改后在进行迁移。

QUERY: CREATE TABLE txxx

(

  ......

 a             varchar(100) default '01'',

  b                varchar(20),

  ......

);

 

修改方法:

ALTER TABLE `txxx`

MODIFY COLUMN `a` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '01' 

 

修改完成后,针对该单表进行迁移

单表迁移配置

vi pg.load.txx

 

load database

from mysql://admin_user:admin_user@192.168.56.113:3306/test1

into pgsql://admin_user:admin_user@192.168.56.114:5432/tdb;

  INCLUDING ONLY TABLE NAMES MATCHING ' txxx';

 

pgloader pg.load.txx

 

Varchar(0)字段处理

在迁移过程中发现某个表的字段定义为varchar(0),导致pgloader 迁移失败。

QUERY: CREATE TABLE t1

(

  ......

  a   varchar(2),

  b  varchar(0),

 ......

);

修改字段长度后,进行单表迁移

 

单表迁移配置

vi pg.load.t1

 

load database

from mysql://admin_user:admin_user@192.168.56.113:3306/test1

into pgsql://admin_user:admin_user@192.168.56.114:5432/tdb;

  INCLUDING ONLY TABLE NAMES MATCHING ' t1';

 

pgloader pg.load.t1


自增问题处理

在mysql中某些主键会使用自增功能AUTO_INCREMENT,但是在postgres中自增特性的字段类型是serial,因此如果使用postgres中的自增功能需要修改表字段类型。在不改变字段类型的情况下来实现postgres中的自增,需要引入序列。因此需要注意序列的权限。

Mysql 表

CREATE TABLE `undo_log` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,

  `branch_id` bigint(20) NOT NULL,

  `xid` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL,

  `context` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL,

  `rollback_info` longblob NOT NULL,

  `log_status` int(11) NOT NULL,

  `log_created` datetime DEFAULT NULL,

  `log_modified` datetime DEFAULT NULL,

  `LAST_UPDATE_TIME` timestamp NULL ,

  PRIMARY KEY (`id`) USING BTREE,

  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

 

Postgres 表

CREATE TABLE undo_log (

    id bigint NOT NULL,

    branch_id bigint NOT NULL,

    xid character varying(100),

    context character varying(128),

    rollback_info bytea NOT NULL,

    log_status bigint NOT NULL,

    log_created timestamp(6) without time zone,

    log_modified timestamp(6) without time zone,

    last_update_time timestamp(6) without time zone

);

 

CREATE SEQUENCE undo_log_id_seq

    START WITH 1

    INCREMENT BY 1

    NO MINVALUE

    NO MAXVALUE

    CACHE 1;

 

ALTER TABLE undo_log_id_seq OWNER TO pms3;

 

ALTER SEQUENCE undo_log_id_seq OWNED BY undo_log.id;

 

ALTER TABLE ONLY undo_log ALTER COLUMN id SET DEFAULT nextval('undo_log_id_seq'::regclass);

 

ALTER TABLE ONLY undo_log

    ADD CONSTRAINT idx_23386_primary PRIMARY KEY (id);

 

CREATE UNIQUE INDEX idx_23386_ux_undo_log ON undo_log USING btree (xid, branch_id);

 

CREATE INDEX ux_undo_log ON undo_log USING btree (xid, branch_id);

 

GRANT SELECT ON TABLE undo_log TO app_fxtb;

GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE undo_log TO app_psr;

GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE undo_log TO mid_psr;

 

GRANT SELECT,UPDATE ON SEQUENCE undo_log_id_seq TO mid_psr;

GRANT SELECT,UPDATE ON SEQUENCE undo_log_id_seq TO app_psr;

GRANT SELECT,UPDATE ON SEQUENCE  undo_log_id_seq TO app_fxtb;


视图对象处理

请注意要等所有的表对象处理完成在创建视图。因为视图中的表存在依赖关联,一旦视图创建完成后,再去修改字段类型,很可能报错误,无法修改成功


权限脚本


性能问题处理

在迁移过程中针对大表数据迁移,会出现内存耗尽现象,该现象常常发生在迁移存在大字段表的过程中。由于每个线程默认读取一定行数的数据,如果行中存在大字段,会导致内存消耗很多,严重得情况下内存耗尽,比如在迁移test1数据时会出现Heap exhausted (no more space for allocation)等报错。因此需要针对大表进行专门性能调优

1:在内存比较充足的服务器上部署pgloader;2:修改每次读取的行数。具体如下:

vi pg.load.a

load database

from mysql://admin_user:admin_user@192.168.56.113:3306/test1

into pgsql://admin_user:admin_user@192.168.56.114:5432/tdb;

 WITH include drop, create tables, create indexes, reset sequences,

    batch rows=3000,batch concurrency=1,prefetch rows=10000;

 

pgloader --verbose pg.load.a >> pg.load.a.log 2>&1

 


对象验证

查看表数量

本脚统计的是tdb数据库下所有表对象的数量。如果是其他实例,请输入对应的database

SELECT

table_schema,

COUNT ( * )

FROM

information_schema.tables d

WHERE

d.table_catalog = 'tdb'

and d.table_schema not in('information_schema','pg_catalog','public')

GROUP BY

table_schema

order by table_schema

 

查看视图数量

本脚统计的是tdb数据库下所有视图对象的数量。如果是其他实例,请输入对应的database

SELECT

table_schema,

COUNT ( * )

FROM

information_schema.views d

WHERE

d.table_catalog = 'tdb'

and d.table_schema not in('information_schema','pg_catalog','public')

GROUP BY

table_schema

order by table_schema

 

查看存储过程,函数数量

SELECT

count(*),routine_schema,routine_type

FROM

information_schema.routines

WHERE

ROUTINE_SCHEMA NOT IN ( 'pg_catalog', 'public', 'information_schema' )

group by routine_schema,routine_type

order by routine_schema,routine_type

 

查看序列数量

SELECT COUNT

( * ),

sequence_schema

FROM

information_schema.sequences d

WHERE

d.sequence_catalog = 'tdb'

GROUP BY

sequence_schema

ORDER BY

sequence_schema

查看触发器数量

SELECT COUNT

( * ),

TRIGGER_SCHEMA

FROM

information_schema.triggers

WHERE

TRIGGER_CATALOG = 'tdb'

GROUP BY

TRIGGER_SCHEMA

order by TRIGGER_SCHEMA


数据验证

验证每个表的数据量

参考脚本:<postgresql获得指定schema下表的精确行数.sql>



最后修改时间:2022-01-06 15:45:04
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论