以前项目多是基于MySQL数据库进行开发,最近有需求需要兼容更多类型的数据库,比如PostgreSQL。那么如何实现快速的数据库表结构迁移,甚至是包括数据迁移呢?这里极力推荐使用开源工具PGLoader,它可以完美的实现从MySQL到PostgreSQL的表结构,包括主键、索引、自增序列迁移,同时支持数据迁移。
PGLoader官网
PGLoader官方源码
https://github.com/dimitri/pgloader
PGLoader官方文档
https://pgloader.readthedocs.io/en/latest/pgloader.html
PGLoader的安装
这里我们使用docker安装
1
2
|
docker run --rm -it ghcr.io/dimitri/pgloader:3.6.9 pgloader --version
docker run --rm -it ghcr.io/dimitri/pgloader:3.6.9 pgloader --help
|
当前最新版本是3.6.9,可以根据需要自行修改。
使用PGLoader迁移数据
方法1:直接一条命令执行
1
2
3
|
docker run --rm -it ghcr.io/dimitri/pgloader:3.6.9 \
pgloader mysql://user1:xxxxxx@10.10.0.22:3306/db_test1 \
pgsql://user1:xxxxxx@10.10.0.23:5432/db_test1
|
这种方法直接明了,但是缺乏定制操作,当数据量大时就会报错而中断
方法2:使用load文件
先建个临时目录用于docker挂载(官方文档或网上其它资料没说这个步骤,但我试了一直说找不到文件,最后还是用这个方法解决)
1
2
|
mkdir /root/tmpdir
cd /root/tmpdir
|
编辑load文件vi my.load
1
2
3
4
5
6
7
|
LOAD DATABASE
FROM mysql://user1:xxxxxx@10.10.0.22:3306/db_test1
INTO pgsql://user1:xxxxxx@10.10.0.23:5432/db_test1
with prefetch rows = 10000
WITH include drop, create tables, create indexes, workers = 8, concurrency = 1
ALTER SCHEMA 'db_test1' RENAME TO 'public'
;
|
说明:
LOAD DATABASE 指定从数据库加载
FROM 源数据库
INTO 目标数据库
WITH 指定 PGLoader 行为
include drop,迁移过程中,PGLoader 会删除目标 PostgreSQL 数据库中在源数据库中同名的任何表。注意备份。
create tables, 配置 PGLoader 根据源数据库数据在目标数据库中创建新表,如果使用 create no tables,则需要手动在目标数据库中创建好对应的表。
ALTER SCHEMA, 在 WITH 语句之后,配置特定 SQL 来告诉 PGLoader 执行其他操作。
执行迁移
1
2
|
docker run -v /root/tmpdir:/tmp --rm -it ghcr.io/dimitri/pgloader:3.6.9 \
pgloader /tmp/my.load
|
更多load文件配置可参考以下例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
LOAD DATABASE
FROM mysql://root@localhost/sakila
INTO postgresql://localhost:54393/sakila
WITH include drop, create tables, create indexes, reset sequences,
workers = 8, concurrency = 1,
multiple readers per thread, rows per range = 50000
SET PostgreSQL PARAMETERS
maintenance_work_mem to '128MB',
work_mem to '12MB',
search_path to 'sakila, public, "$user"'
SET MySQL PARAMETERS
net_read_timeout = '120',
net_write_timeout = '120'
CAST type bigint when (= precision 20) to bigserial drop typemod,
type date drop not null drop default using zero-dates-to-null,
-- type tinyint to boolean using tinyint-to-boolean,
type year to integer
MATERIALIZE VIEWS film_list, staff_list
-- INCLUDING ONLY TABLE NAMES MATCHING ~/film/, 'actor'
-- EXCLUDING TABLE NAMES MATCHING ~<ory>
-- DECODING TABLE NAMES MATCHING ~/messed/, ~/encoding/ AS utf8
-- ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'
-- ALTER TABLE NAMES MATCHING ~/_list$/ SET SCHEMA 'mv'
ALTER TABLE NAMES MATCHING ~/_list$/, 'sales_by_store', ~/sales_by/
SET SCHEMA 'mv'
ALTER TABLE NAMES MATCHING 'film' RENAME TO 'films'
ALTER TABLE NAMES MATCHING ~/./ SET (fillfactor='40')
ALTER SCHEMA 'sakila' RENAME TO 'pagila'
BEFORE LOAD DO
$$ create schema if not exists pagila; $$,
$$ create schema if not exists mv; $$,
$$ alter database sakila set search_path to pagila, mv, public; $$;
|
该配置来自官方文档
https://pgloader.readthedocs.io/en/latest/ref/mysql.html#using-advanced-options-and-a-load-command-file