迁移 IBM Db2 LUW 到 Amazon Aurora PostgreSQL 或 Amazon

将 IBM Db2 LUW 迁移到 Amazon Aurora PostgreSQL 或 Amazon RDS for PostgreSQL

关键要点

在这篇文章中,我们将概述如何将 IBM Db2 LUW 数据库迁移到 Amazon Aurora PostgreSQL 兼容版 或 Amazon Relational Database Service (Amazon RDS) for PostgreSQL。讨论了架构转换过程中可能遇到的挑战,以及如何通过原生的 EXPORT 和 COPY 命令执行数据迁移。此外,还会探讨如何自动化数据迁移和进行 架构 和数据验证。

本文重点涵盖了 Db2 LUW 迁移的两个主要里程碑:

使用 AWS Schema Conversion Tool (AWS SCT) 转换 Db2 LUW 源架构使用原生的内置工具将数据从 Db2 LUW 迁移到 Aurora PostgreSQL 兼容版

前期准备

在开始数据库迁移之前,我们建议您完成一项预迁移阶段,以准备您的数据库。有关更多信息,请参考 数据库迁移开始之前您需要了解的事项。总体而言,您应执行以下操作:

删除或弃用不再需要的对象,例如由于应用程序或业务流程增强而遗留的冗余表、存储过程、函数或触发器。删除临时表和过去维护的备份表。清理或归档不需要存储到 Amazon Simple Storage Service 的历史数据。

现在,让我们开始吧!

架构转换

在开始迁移之前,强烈建议您评估一下数据库迁移所需的工作和可行性。您可以使用 AWS SCT 生成 数据库迁移评估报告,该报告提供有关架构转换的详细行动项目。您可以利用此报告根据复杂性估算架构转换的工作量。有关下载和安装 AWS SCT 的信息,请参阅 安装、验证和更新 AWS SCT。

在以下各节中,我们将介绍在从 Db2 LUW 到 PostgreSQL 迁移过程中遇到的一些常见场景。

分区表

分区表是一种数据组织方式,根据一个或多个表属性称为 分区键的值将表数据划分到多个存储对象称为数据分区中。Db2 LUW 和 PostgreSQL 都支持表分区,但存在一些差异。

首先,Db2 LUW 数据库中的范围分区表有 INCLUSIVE 和 EXCLUSIVE 子句来设置边界值,而 PostgreSQL 从 v15 开始仅支持起始边界的 INCLUSIVE 和结束边界的 EXCLUSIVE。

下面是一个示例,表 DIMSPORTINGEVENT 存储了按月的数据。 在 Db2 LUW 中,分区的下限是月份的开始01,而上限是月份的结束30/31。 在 PostgreSQL 中,下限是月份的开始1,上限是下个月的开始,这样就将月份末日期保留在同一分区中。

Db2 LUWsqlCREATE TABLE SAMPLEDIMSPORTINGEVENT ( SPORTINGEVENTID BIGINT NOT NULL SPORTLOCATIONID BIGINT NOT NULL SPORTTYPENAME VARCHAR(15 BYTE) NOT NULL HOMETEAMID BIGINT NOT NULL AWAYTEAMID BIGINT NOT NULL STARTDATETIME DATE NOT NULL SOLDOUT INTEGER DIMSPORTTEAMSPORTTEAMID INTEGER DIMSPORTTEAMSPORTTEAMID1 INTEGER PRIMARY KEY(SPORTINGEVENTID))PARTITION BY RANGE(STARTDATETIME) ( PART JAN2017 STARTING(20170101) ENDING(20170131) PART FEB2017 STARTING(20170201) ENDING(20170228) PART MAR2017 STARTING(20170301) ENDING(20170331))

PostgreSQLsqlCREATE TABLE IF NOT EXISTS sampledimsportingevent ( sportingeventid bigint NOT NULL sportlocationid bigint NOT NULL sporttypename character varying(15) NOT NULL hometeamid bigint NOT NULL awayteamid bigint NOT NULL startdatetime date NOT NULL soldout integer dimsportteamsportteamid integer dimsportteamsportteamid1 integer CONSTRAINT sql220915081554000 PRIMARY KEY (sportingeventid startdatetime)) PARTITION BY RANGE (startdatetime)

CREATE TABLE sampledimsportingeventjan2017 PARTITION OF sampledimsportingevent FOR VALUES FROM (20170101) TO (20170201)CREATE TABLE sampledimsportingeventfeb2017 PARTITION OF sampledimsportingevent FOR VALUES FROM (20170201) TO (20170301)CREATE TABLE sampledimsportingeventmar2017 PARTITION OF sampledimsportingevent FOR VALUES FROM (20170301) TO (20170401)

在 PostgreSQL 中,主键需要包括分区键,而在 Db2 LUW 中并没有此限制。 添加分区键后,现有插入语句可能会导致 PostgreSQL 中的重复项。

以下表格包含 sampledimsportingevent 表中的示例数据条目。

现有主键 (Db2 LUW) (SPORTINGEVENTID)插入操作新主键 (PostgreSQL) (sportingeventid startdatetime)插入操作1234成功1234 20170102成功1234失败1234 20170103成功

这可以根据您的业务逻辑进行调整。例如,解决方案可能包括识别其他主键或唯一键,或者从表中删除分区。在决定从表中删除分区或添加其他键之前,您需要验证功能和非功能要求。

最后,Db2 LUW 分区列可以在生成的列上定义,但在 PostgreSQL v15 及以下版本中无法实现。有关更多信息,请参阅 生成的列。

云梯加速器免费

序列

您可能在 SEQUENCE 语句中使用了 CACHE 选项来提高性能和调整。在使用时,DB2 在内存中预分配指定数量的顺序值。这有助于最小化锁争用。在 Db2 LUW 服务器上,缓存的值对连接是可见的。尽管 PostgreSQL 中存在 cache 关键字,但它仅对正在访问序列的连接或会话进行缓存。如果新连接或会话访问序列,则会为该会话缓存一组新值。比较下面的代码块。

Db2 LUWsqlCREATE TABLE SAMPLEPLATFORM ( PLATFORMID INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 NO CYCLE CACHE 20 NO ORDER ) PLATFORMNAME VARCHAR(255) NOT NULL )

PostgreSQLsqlCREATE TABLE sampleplatform( platformid BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY ( MAXVALUE 2147483647 MINVALUE 1 NO CYCLE CACHE 20) platformname CHARACTER VARYING(255) NOT NULL)

Db2 LUWshell

session 1

db2 insert into PLATFORM(PLATFORMNAME) values(EC2)DB20000I The SQL command completed successfully

db2 select from PLATFORMPLATFORMID PLATFORMNAME 1 EC2

session 2

db2 insert into PLATFORM(PLATFORMNAME) values(ECR)DB20000I The SQL command completed successfully

迁移 IBM Db2 LUW 到 Amazon Aurora PostgreSQL 或 Amazon

db2 select from PLATFORMPLATFORMID PLATFORMNAME 1 EC2 2 ECR

PostgreSQLshell

session 1

postgres=gt insert into PLATFORM(PLATFORMNAME) values(ECR)INSERT 0 1postgres=gt select from PLATFORM platformid platformname 1 ECR(1 row)

session 2

postgres=gt insert into PLATFORM(PLATFORMNAME) values(EC2)INSERT 0 1postgres=gt select from PLATFORM platformid platformname 1 ECR 21 EC2(2 rows)

身份列自动为添加到表中的每一行生成唯一的数字值。通过 INCREMENT BY 子句,您可以设置每个新行的后续值增加多少。请注意,迁移后身份列不会在目标上推进。因此,您应重置序列为下一个值,以帮助防止重复。使用 pggetserialsequence 函数可以返回与身份列相关的序列的名称。以下匿名代码块可以帮助您生成 SQL 语句以重新启动身份序列。

以下代码片段生成一个 SELECT SETVAL 语句,以使用最大值 1 重启身份序列:

sqlDO BLOCKDECLARE lrecord RECORD lobjectname varchar lseqname varchar lsql varchar ltabschema varchar = sampleBEGIN for loop FOR lrecord in SELECT tableschema tablename columnname from informationschemacolumns where tableschema = ltabschema and isidentity = YES and identitygeneration = BY DEFAULT LOOP create object name RAISE NOTICE lrecord lrecord lobjectname = NULL lobjectname = concatws( lrecordtableschema lrecordtablename) RAISE NOTICE lobjectname lobjectname get sequence name lseqname = NULL SELECT pggetserialsequence(lobjectname lrecordcolumnname) INTO lseqname RAISE NOTICE lseqname lseqname lsql = NULL lsql = concatws( SELECT SETVAL( lseqname (SELECT coalesce(MAX( lrecordcolumnname )0) 1 FROM lobjectname ))) RAISE NOTICE lsql lsql EXECUTE lsql END LOOPENDBLOCK

物化查询表

物化查询表 (MQT) 是通过查询定义的,它们有助于提高 Db2 LUW 中复杂查询的性能。PostgreSQL 具有 物化视图 (MV) 来实现类似的功能要求。以下表格比较了这些功能。

Db2 LUWPostgreSQL被称为 物化查询表被称为 物化视图两种类型:系统管理和用户管理,使用 MAINTAINED BY 子句标识仅用户管理系统管理物化查询表可以使用 REFRESH IMMEDIATE 选项自动刷新本地仅支持手动刷新,通过触发器可实现自动刷新支持全量和增量刷新仅支持全量刷新刷新期间独占表锁使用 CONCURRENTLY 关键字支持刷新而不锁定选择语句优化器会在查询重写阶段自动考虑 MQT优化器不会在查询重写阶段考虑 MV允许对用户管理的 MQT 进行 DML 语句不允许对 MV 执行 DML 语句

您可以将 Db2 LUW 的用户管理 MQT 转换为 PostgreSQL 的物化视图。通过将 MQT 转换为常规表并添加触发器,根据源表上的数据操作语言 (DML) 操作来刷新数据,可以将 Db2 LUW 的系统管理 MQT 转换为 PostgreSQL。

唯一索引

在 Db2 LUW 中,唯一索引将 NULL 值视为相等。这意味着如果唯一索引中有一个允许 NULL 的列,则只会出现一次。然而,PostgreSQL 将 NULL 视为不同的值。因此,您可以在唯一索引的列中有多个 NULL 值。比较下面的代码块。

Db2 LUWsqlCREATE TABLE SAMPLETESTUQIDX ( ID INTEGER NOT NULL NAME CHAR(20) NOT NULL PANCARD VARCHAR(50) )

ALTER TABLE SAMPLETESTUQIDX ADD PRIMARY KEY(ID)

CREATE UNIQUE INDEX SAMPLEUPANCARD ON SAMPLETESTUQIDX (NAME PANCARD)

PostgreSQLsqlCREATE TABLE IF NOT EXISTS testuqidx ( id integer NOT NULL name character(20) NOT NULL pancard character varying(50) CONSTRAINT testuqidxpkey PRIMARY KEY (id))

CREATE UNIQUE INDEX IF NOT EXISTS upancard ON testuqidx (name pancard)

Db2 LUWshelldb2inst1@ip172 db2 insert into SAMPLETESTUQIDX values ( 1 Nikhil1234asd)DB20000I The SQL command completed successfullydb2inst1@ip172 db2 insert into SAMPLETESTUQIDX values ( 2 NikkiNULL)DB20000I The SQL command completed successfullydb2inst1@ip172 db2 insert into SAMPLETESTUQIDX values ( 3 NikkiNULL)DB21034E The command was processed as an SQL statement because it was not a valid Command Line Processor command During SQL processing it returned SQL0803N One or more values in the INSERT statement UPDATE statement or foreign key update caused by a DELETE statement are not valid because the primary key unique constraint or unique index identified by 2 constrains table DB2INST1TESTUQIDX from having duplicate values for the index key SQLSTATE=23505

PostgreSQLshelllab=gt insert into TESTUQIDX values ( 1 Nikhil1234asd)INSERT 0 1lab=gt insert into TESTUQIDX values ( 2 NikkiNULL)INSERT 0 1lab=gt insert into TESTUQIDX values ( 3 NikkiNULL)INSERT 0 1

您可以在 PostgreSQL 中使用部分索引模拟 Db2 LUW 的唯一索引行为最多到版本 14:

sqlcreate unique index IF NOT EXISTS upancard ON publictestuqidx (name pancard) where pancard is not nullcreate unique index IF NOT EXISTS upancard1 ON publictestuqidx (name) where pancard is null

与 Db2 LUW 类似的插入失败

sqlmiglab=gt select from TESTUQIDX id name pancard 1 Nikhil 1234asd 2 Nikki (2 rows)

miglab=gt insert into TESTUQIDX values ( 3 NikkiNULL)ERROR duplicate key value violates unique constraint upancard1DETAIL Key (name)=(Nikki ) already existsmiglab=gt

在 v15 或更高版本中,您可以通过在创建索引语句中添加 NULLS NOT DISTINCT 来实现。

成功转换架构后,下一步是验证。您可以通过验证 Db2 LUW 和 PostgreSQL 之间对象的数量和属性是否匹配来进行架构验证,可以使用本文提供的 SQL 示例 验证从 IBM Db2 LUW 迁移到 Amazon Aurora PostgreSQL 或 Amazon RDS for PostgreSQL 的数据库对象。您可以将此代码作为脚本或批处理的一部分执行,以实现此里程碑的自动化。

使用原生 EXPORT 和 COPY 命令迁移数据

这个场景是一个异构迁移,仅需要一次完整加载

给我们留言