从Oracle迁移到PostgreSQL时的挑战 - 以及如何克服它们

英文原文地址:点击这里

David Rader是OpenSCG的工程副总裁。 OpenSCG是AWS咨询合作伙伴和PostgreSQL的领先专家,帮助客户在内部和云中迁移,操作和优化PostgreSQL和其他数据平台。(OpenSCG已于2018年被Amazon收购)

在之前的文章中,我们研究了成功进行数据库迁移的整体方法,以及如何选择要迁移的第一个数据库。在这篇文章中,让我们看一些迁移挑战和克服它们的技巧。

_config.yml

当组织希望从Oracle迁移到开源PostgreSQL数据库时,他们通常会关注高级功能,高性能,坚如磐石的数据完整性,灵活的开源许可以及包括AWS在内的公共云提供商的轻松可用性。 但是迁移的道路并不总是顺利,知道如何避免各种坑可以帮助确保您的迁移成功。

我在这篇文章中写到的挑战产生的影响范围很广,从开始的便利性和易用性,到迁移数据库的性能降低,都可能使迁移变得不可能。 由于这是可怕的一个任务,让我们从可能只会使现有应用程序无法迁移的挑战开始。

打包应用程序

PostgreSQL支持大多数开发语言,包括Java,C#,Python,PHP,C / C ++,JavaScript / Node.js,Go等。 PostgreSQL完全符合ACID标准,并且非常符合ANSI SQL:2008标准。 但是,如果您使用的是其供应商未在PostgreSQL上进行认证的打包软件应用程序,则迁移可能没有成功的希望。

如果您想将商业ERP / CRM /会计应用程序从Oracle迁移到PostgreSQL,您可能必须让您的供应商将PostgreSQL添加到其支持的数据库列表中,或者迁移到新的业务应用程序。 但对于您控制并拥有源代码的应用程序而言,这不是问题。

数据类型和架构转换

现在我们已经涵盖了最大的挑战,让我们回到最简单的问题之一。 PostgreSQL有一套全面的内置数据类型,并支持自定义扩展类型。 核心Oracle数据类型可以轻松映射到PostgreSQL类型(请参阅这个简单的备忘单进行映射)。 表的大多数映射和转换可以使用AWS模式转换工具(AWS SCT)或其他迁移工具自动完成。

一些PostgreSQL数据类型比相应的Oracle类型更容易使用。 例如,Text类型可以存储最多1GB的文本,并且可以像SQL和varchar字段一样在SQL中处理。 它们不需要特殊的大对象函数,如字符大对象(CLOB)。

但是,需要注意一些重要的差异。 PostgreSQL中的Numeric字段可用于映射任何Number数据类型。 但是当它用于连接时(例如用于外键),它的性能比使用int或bigint要差。

带有时区字段的PostgreSQL时间戳与带有时区字段的Oracle时间戳略有不同 - 它实际上等同于Oracle的带有本地时区的时间戳。 这些小差异可能导致性能问题或需要彻底测试的细微应用程序错误。

迁移数据

转换模式并调整表以最好地满足您的特定应用程序后,就是迁移数据的时候了。 对于较小的(100 GB或更少)数据库,此过程相当简单。 使用AWS Data Migration Service(AWS DMS)HVR等工具,您可以创建在Amazon EC2实例上运行的数据迁移作业,连接到本地Oracle数据库,并将数据传输到Amazon RDS for PostgreSQL实例。 您需要验证目标数据库中的数据。 然后在开发,测试以及最终的生产环境中运行几次迁移,并解决出现的任何问题。

如果您对迁移过程感到满意,请在生产中再次运行该过程。 使用AWS DMS复制实例迁移大量现有数据并加入当前更改的事务。 然后保持迁移服务运行,以确保目标数据库与实时系统中的更改保持同步。

更大的数据量

对于更大的数据量 - 例如,超过1 TB - 纯粹的在线数据迁移可能过于耗时或占用过多的可用带宽。 在这种情况下,您应该使用导出,重新加载和同步的方法。 在此方法中,您导出最大的表。 然后,您可以压缩并将它们推送到Amazon S3,也可以使用AWS Snowball将它们传输到AWS区域并加载到Amazon S3。 数据在Amazon S3之后,您可以将数据文件批量加载到PostgreSQL。

使用基于日期的分区可以更轻松地选择和隔离脱机移动的数据。 具有基于时间戳记录的不变的历史数据可以导出到已知的时间点,使用AWS DMS迁移该点之后的任何数据。 或者,您可以使用Oracle日志序列号(LSN)或特定于应用程序的顺序ID作为导出和迁移作业的截止点。

架构清理

迁移是清理架构和应用程序的某些部分的好时机。 例如,如果您在数据库中存储文件(PDF,图像等),那么现在是将它们分解到自己可靠的Amazon S3存储中的好时机。 减少数据库的大小和备份和还原操作所需的时间,并通过更灵活地处理文件来提高应用程序的灵活性。

如果您有静态历史数据,并且应用程序从未使用过静态历史数据,则可以将其完全清除,或者将其移动到单独的存档数据存储中。 此数据存储可以是性能较低(且成本较低)的PostgreSQL数据库,也可能是Amazon S3支持的Amazon Athena或Apache Spark系统,适用于对冷数据的不频繁查询。

另外,如果您混合了在线事务处理(OLTP)和分析式数据访问,那么从一站式工具Oracle设置转变为使用单独的仓库进行报告和分析可以提高应用程序响应能力和分析能力能力。 可以选择创建基于Postgres-XL的专用仓库,也可以使用Amazon Redshift作为强大的托管仓库。

总之,迁移数据需要规划和实践,但这是一个完全可以解决的挑战。

迁移代码

Oracle-to-PostgreSQL迁移过程中最耗费精力的工作通常是将代码移植到PostgreSQL中。 这适用于数据库中的存储过程,包和函数以及读取和写入数据库的应用程序代码。

数据库代码

PostgreSQL在很多方面与Oracle类似。 主要的过程编程语言PL/pgSQL与PL/SQL类似,大多数数据库管理员(DBA)和开发人员都可以轻松学习语法。 AWS Schema Conversion Tool(AWS SCT)或开源Ora2Pg等自动化工具通常可以自动转换70%以上的数据库代码,以便正常工作。

自动转换包括将特定于Oracle的函数转换为ANSI标准函数(例如,从nvl()转移到coalesce()),将旧语法(例如用于外部联接的加号(+))更改为标准外部联接语法,以及为Oracle认为可选但PostgreSQL必需的子选择添加别名。 在这些情况下,转换后的代码与Oracle和PostgreSQL兼容。 在完全迁移之前,它实际上可以合并到您当前的应用程序代码库中并部署在现有数据库中。

自动化工具还可以转换使用特定于数据库的语法的代码,例如使用Oracle的sequence.nextval和PostgreSQL的nextval(sequence)进行序列处理,或者在存储过程中执行动态SQL的稍微不同的语法。 这些更改与Oracle不兼容,因此仅用于目标PostgreSQL系统。

其余代码必须手动转换,因为SQL和PL / SQL太复杂,工具无法完美地解析和转换,或者因为没有可以自动应用的精确一对一转换。 许多此类案例对于有经验的开发人员和DBA在了解PostgreSQL方法和所涉及的应用程序逻辑时进行转换是微不足道的。

利基(niche)功能:自主交易(autonomous transactions),collect all和BFILE

某些Oracle功能PostgreSQL不支持,或者不能通过扩展或解决方法处理这些功能。 例如,PostgreSQL不直接支持自动事务,这些事务使一个存储过程的更改能够在回滚的较大事务中提交。 常见的解决方法是使用DBLink“远程”连接到同一数据库。 您执行要作为“远程”调用提交的函数,该函数被视为单独的连接和单独的事务。

同样,核心PostgreSQL不支持外部组织的表或直接访问数据库文件系统上的文件。 但是,使用外部数据包装器(FDW)可以实现这两种功能。

一些常见的Oracle软件包(如DBMS_OUTPUT)受开源orafce和AWS兼容性扩展的支持,可以降低转换成本。 其他的,如UTL_FILE,UTL_HTTP和SMTP包,可以通过扩展支持。 但您应该检查这是否是正确的架构解决方案,或者您的应用程序架构是否应作为转换的一部分进行更新。 您需要验证您正在考虑的扩展是否在Amazon RDS托管环境中受支持,否则您可能无法使用Amazon RDS。

应用程序代码

如前所述,PostgreSQL在编程语言方面有广泛的支持,并且每种主流开发语言都有可用的驱动程序,还有许多其他驱动程序。根据您的应用程序体系结构和数据库连接层,您可能只需要进行少量更改,或者可能需要进行重大的移植更改。

例如,转换使用通用JDBC类(不是特定于Oracle的类)的基于Java的应用程序并且始终在代码中调用没有SQL的存储过程(动态构建或硬编码)相当容易。如果使用对象关系映射(ORM)(如Hibernate或JCA),将开发语言从Oracle切换到PostgreSQL可能非常容易。当然,还有一些小的区别,例如,如果使用分区,则所需的PostgreSQL触发器会更改从插入返回的记录计数会让Hibernate变傻。因此,您需要为更新分区表的Hibernate查询添加注释。

对于这些类型的简单案例,您甚至可以使用AWS SCT扫描Java或.NET代码以查找SQL语句并将SQL转换为与PostgreSQL兼容的SQL,类似于为PL/SQL完成的转换。

但是,如果您使用嵌入式SQL(如Oracle的Pro*C),链接到Oracle特定的库(如OCI或Oracle JDBC类),或者根据应用程序条件动态构建SQL,则应用程序代码转换将更加复杂。 PostgreSQL支持嵌入式SQL(ECPG)或libpq库的C/C ++。 但这些与Oracle产品不兼容。

同样,更改动态构建SQL的应用程序代码需要充分了解应用程序逻辑和足够的测试,以确保功能按预期工作。 我们与客户合作自动化这些迁移的某些方面,但仍需要应用程序维护团队的关注。

事务控制和异常处理

每个应用程序都必须确保正确的事务管理和错误处理 - 也就是我们如何防止极端情况,运行时故障和意外用户输入创建错误数据。 PostgreSQL具有强大的事务处理能力,支持完整的ACID语义和不同的隔离级别。 PostgreSQL还可以优雅地处理运行时错误,并为调用代码-PL/pgSQL或应用程序提供可靠的错误代码和消息。但PostgreSQL内部处理这些内容的方式与Oracle需要更改应用程序代码或设计的行为方式存在一些差异。

首先,PostgreSQL不允许在PL/pgSQL内部进行事务控制 - 您无法在存储过程中提交或回滚事务。调用存储过程的应用程序必须执行事务管理 - 启动和提交或回滚。存储过程在该调用事务上下文中执行。显然,如果您的现有数据库代码在过程中具有事务管理,则必须对其进行修改。

其次,当事务中发生运行时异常时,必须先回滚该事务,然后才能对连接执行任何语句。当您在应用程序日志中发现以下错误消息时,通常会看到此消息:

ERROR: current transaction is aborted, commands ignored until end of transaction block. 错误:当前事务被中止,命令被忽略直到事务块结束。

此消息表示发生错误,错误被忽略,并且执行了另一个语句(SELECTINSERTEXECUTE,以及任何其他的…)然后第二个语句失败,因为事务已处于错误状态(已中止)。当您看到此消息时,请仔细检查数据库调用和异常处理。确保在可能发生错误的任何地方(任何数据库调用),您在尝试其他数据库操作之前检查错误或设置异常处理程序和ROLLBACK(或ROLLBACK到保存点,或关闭连接)。

第三,对于应用程序逻辑和解决上述错误,您必须进行异常处理。在PL/pgSQL中,使用BEGIN ... EXCEPTION ... END块可以让您的代码捕获发生的错误。此块在块之前自动创建一个保存点,并在发生异常时回滚到该新保存点。然后,您可以根据是否存在错误来确定要执行的逻辑。但是,异常块因为它们创建了一个保存点而非常昂贵。如果您不需要捕获错误,或者您计划简单地将错误提交回调用应用程序,则根本不要使用异常块。让原始错误流向应用程序。

类似地,Java,嵌入式SQL和其他语言具有捕获异常的机制。检查应用程序以确保在数据库调用周围进行适当的错误处理。如果应用程序当前捕获并忽略该异常,则必须先修改它以回滚事务,然后才能发出新的数据库调用。如果应用程序希望在异常之前保留部分事务更改,则可能必须将保存点添加到应用程序代码并回滚到保存点以在异常后继续。

请注意,就像PL/pgSQL中的异常块一样,添加保存点确实会影响性能。所以只在需要的地方使用它们,而不是在每个数据库调用中使用。例如,假设您正在保存标头记录以及子记录,并且如果出现异常,您将回滚整个事务。在这种情况下,您不需要在插入标头记录后创建保存点,因为如果子记录失败,则回滚插入。

最后,您必须将应用程序期望从Oracle获得的错误代码和异常类型映射到PostgreSQL。某些错误代码(例如100 no record found代码)在两者上都是相同的,但其他错误代码是不同的。根据您的编程语言,如果要捕获特定于Oracle的JDBC异常,则必须将这些特定异常替换为通用跨数据库异常或切换到PostgreSQL特定的异常。

确保应用程序正确处理事务和错误是迁移的关键部分,通常需要更改数据库和应用程序代码。

技能

多年来,您的DBA和开发人员在您当前的技术方面积累了大量经验。这些经验包括使用各种高级功能,调整性能以及保持系统稳定和运行。迁移到新技术需要学习新技能,开发新方法来解决问题,并放弃旧的做事方式。不要低估经验丰富的DBA在新平台上支持任务关键型系统所需的时间。

您还必须意识到,虽然Oracle和PostgreSQL都是关系数据库,并且支持大多数用于创建表和查询数据的相同SQL语法,但内部结构却不同。所以他们在某些情况下表现不同。

例如,PostgreSQL的多版本并发控制(MVCC)与Oracle的回滚段非常不同,即使它们都为ACID事务提供了基础。习惯于为一个人设计应用程序的开发人员或者用于优化性能的DBA,如果他们在另一个上使用相同的技术,可能会遇到一些令人讨厌的速度障碍。

在迁移过程的早期阶段对PostgreSQL团队进行培训很有帮助。 他们将更加轻松地执行迁移,并且能够更快地交付有效的应用程序和数据库。 另外,如果他们在开始转换代码之前了解差异,他们可能能够避免一些令人讨厌的进度变动。

最大限度地减少停机时间

成功迁移的关键要求是不要破坏您的业务。 这意味着您必须确保正确迁移数据,应用程序正常运行,并且性能提供良好的用户体验。 它还意味着当您的应用程序无法供用户或客户使用时,减少停机时间。

这些步骤有助于减少生产转换所需的时间,从归档旧数据到使用AWS DMS迁移并保持正在进行的事务复制,以确保您的代码经过全面测试。 通过编写部署步骤脚本并在测试和登台环境中多次排练,您可以确保您的团队为生产切换做好充分准备。 使用AWS资源意味着您可以启动和停止这些测试环境,而不会产生大型数据库服务器安装的全部费用。

同步目标DB

如果使用脱机和复制方法(如AWS DMS)的组合迁移所有数据,则可以在启动转换过程之前获得已迁移数据库的完全数据,并可立即使用的副本。 您不需要经历可怕的练习来计算转换1TB数据库的速度,或者给管理者提供有关在周六维护窗口期间迁移的表数量的持续更新。

加快迁移速度的技巧

在这篇文章中,我讨论了从Oracle迁移到PostgreSQL时可能遇到的一些问题,以及克服挑战的一些技巧。

以下策略有助于缩短完成迁移所需的总时间: 培训:您的首席架构师,DBA和开发人员必须了解Oracle和PostgreSQL之间的差异以及迁移应用程序的正确方法。为期一周的培训课程有助于避免长时间的延误,因为他们很难在项目后期解决意外的惊喜。

测试:测试应用程序是迁移总工作量的重要组成部分。具有可在应用程序或数据访问层运行的自动化测试有助于显着缩短测试和重复周期时间。

两步:如果您的应用程序需要大量SQL修改或代码更改以实现兼容性,请通过尽可能多地移动到适用于Oracle和PostgreSQL的ANSI标准代码来减少维护两个代码分支的持续时间。然后在现有生产系统中部署这些更改。这也减少了最终转换中必须测试的更改。

脚本:使用AWS SCT等自动化工具。与合作伙伴合作,可以为主要代码清理构建自动转换脚本,而不是依靠强力来修改数千个代码文件。

Written on September 7, 2018