好风凭借力 – 使用 Babelfish 加速迁移 SQL Server 的代码转换实践

亚马逊云科技
0
0
{"value":"#### **前言**\n\n尽管毫无疑问,传统商业许可数据库拥有丰富的功能和完善的支持,但其严格的定价模式、繁琐的许可条款以及较高的总体拥有成本(**TCO**)使得企业希望采用成本更低的开源解决方案。某些方面,开源数据库以更低的成本提供了相同甚至更好的功能。从商业数据库迁移到开源数据库可为企业在许可和支持方面节省大量成本。\n\n**PostgreSQL** 是企业级的,功能丰富的开源数据库系统,它高度可靠且性能卓越,非常适合实时和任务关键型应用程序。**Amazon Aurora** 是一种关系数据库服务,既有高端商用数据库的高速度和可用性,也有开源数据库的简单性和成本效益。Aurora 与 MySQL 和 PostgreSQL 完全兼容,使现有应用程序和工具无需修改即可运行。与典型的 PostgreSQL 数据库相比,它将性能提高了三倍,并且增加了可扩展性、持久性和安全性。\n\n从传统的 **SQL Server** 数据库迁移可能非常耗时且需耗费大量资源,任何迁移都涉及三个主要步骤:移动架构、迁移数据和修改客户端应用程序。正如下图中我们所见:迁移数据库时,您可以使用 **Amazon Schema Conversion Tool(SCT)** 配合 **Amazon Database Migration Service (DMS)** 自动迁移数据库架构和数据,但迁移应用程序本身时,通常需要完成更多的工作,包括重写与数据库交互的应用程序代码,将 T-SQL 代码迁移到 PL/pgSQL 中,这是复杂、耗时且有风险的。\n\n![image.png](https://dev-media.amazoncloud.cn/cf75c1a1c18447c98f932683a84544af_image.png)\n\n**Babelfish for Aurora PostgreSQL** 是 Amazon Aurora PostgreSQL 兼容版本的一项新功能,可以理解 Microsoft SQL Server 专有的 SQL 语言 T-SQL,并支持相同的通信协议,因此,修改 SQL Server 上运行的应用程序并将其移动到 Aurora 所需的工作量将减少,从而可实现更快、风险更低且更具成本效益的迁移。\n\nBabelfish 通过支持 Aurora PostgreSQL 的 Microsoft SQL Server 数据类型、语法和函数来支持 T-SQL 和 SQL Server 行为。但请注意,Babelfish 并不提供对 T-SQL 的100%完整支持,仍然有一些**差异和限制**,某些情况下需要做手工的代码转换。\n\n本文将列举并演示一些高频及常见的典型代码转换案例,帮助您更高效快速地完成迁移工作。\n\n\n了解更多Babelfish for Aurora PostgreSQL信息:\n[https://aws.amazon.com/cn/rds/aurora/babelfish/](https://aws.amazon.com/cn/rds/aurora/babelfish/)\n\n了解更多Babelfish 的 Aurora PostgreSQL 与 SQL Server 间的区别信息:\n[https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-compatibility.html](https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-compatibility.html)\n\n### **环境准备**\n在开始我们的演示之前,假设在您的工作环境,已有一个准备迁移的 SQL Server 源库,那么除此之外,您还需要设置好以下相关的组件:\n\n- **Babelfish Compass**\n这是一个开源的 SQL Server 迁移到 Babelfish 的语法评估工具,可以在 **GitHub** 上下载。它能在 Windows 和 Linux 平台下运行,需要 Java 环境支持,当前的版本是 v2022-04。\n\n- **Babelfish for Aurora PostgreSQL**\nBabelfish 从2021年秋发布第一个版本1.0.0开始,目前版本已经更新到1.2.1,对应的 Aurora PostgreSQL 版本是13.6。您可以根据**官方文档**说明来操作,只需简单几步即可创建一个 Babelfish for Aurora PostgreSQL 集群环境。配置过程中需要注意的就是数据库迁移模式的选择,还有如果有中文数据的话那么在排序规则中请选择“chinese_prc_ci_as”。\n![image.png](https://dev-media.amazoncloud.cn/79a757fb8e644d86b2ba8dc2caeede62_image.png)\n\n到目前为止,一个包含 SQL Server 源和 Aurora PostgreSQL 目标以及迁移评估工具的环境已经准备好。接下来,请参考这个博客的内容,您只需要花短短的几分钟就能**生成一个 Babelfish 迁移评估报告**。\n\n了解更多 GitHub 信息:\n[https://github.com/babelfish-for-postgresql/babelfish_compass](https://github.com/babelfish-for-postgresql/babelfish_compass) \n\n了解更多 官方文档 信息: [https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-create.html](https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-create.html) \n\n生成一个 Babelfish 迁移评估报告请参考:\n[https://aws.amazon.com/cn/blogs/database/migrate-from-sql-server-to-amazon-aurora-using-babelfish/](https://aws.amazon.com/cn/blogs/database/migrate-from-sql-server-to-amazon-aurora-using-babelfish/) \n\n### **代码转换**\n#### **1. 转换评估**\nBabelfish Compass 工具生成的评估报告是评估迁移工作内容和工作量的指引,您可以根据其中列出的需要修改的项目,逐一编写SQL代码转换内容。\n\n评估报告的 Summary 章节列出了迁移SQL Server 源到 Babelfish 目标的 T-SQL 的语法特性兼容统计,包括支持、不支持、语义审查、手动审查及可忽略项。其中最关键的是不支持特性的内容,这些含有不支持特性的 SQL 语句,如果不作修改,在 Babelfish for Aurora PostgreSQL 环境中大部分执行会报错:“**‘???’ is not currently supported in Babelfish**”,而其他的一些 SQL 语句虽然没有报错,但不会真正生效。\n\n![image.png](https://dev-media.amazoncloud.cn/f967a35d0d3846eb9876b183b6f809f5_image.png)\n\n在评估报告中我们可以查看这些不支持特性的 SQL 分类统计,下图中的评估报告列出了每一类不支持特性的 SQL 语句,它显示了我们的案例所用的DDL脚本在 Babelfish 中不支持的特性主要有对表增加约束语句,Merge 语句、修改数据库、修改角色、执行某些系统存储过程等。\n\n![image.png](https://dev-media.amazoncloud.cn/0a5dfd0bc3a54c479d7b9af62705bd08_image.png)\n\n#### **2.转换原则**\n\n**Babelfish 为 Aurora PostgreSQL 数据库集群提供了一个额外的端点,使其能够了解 SQL Server 线路级协议和常用的 SQL Server 语句**。迁移之后,您仍然可以使用相同的 T-SQL 开发工具和驱动,连接到TDS端口完成相关的开发。\n\n您也可以使用原生 PostgreSQL 连接在 PostgreSQL 这一端做开发,再从 T-SQL 这端进行调用。这一种兼容模式,能帮助我们解决大部分的 Babelfish 对T-SQL的兼容性问题。\n\n- **选择转换模式**:如上所述,对于部分不支持的 SQL 语句,我们可以选择在 T-SQL 中进行改写,也可以在 PostgreSQL 中修改再从 T-SQL 中调用。转换的原则是根据应用的连接开发模式而定,例如 .net 应用连接到 TDS 端开发,那么首选转换模式就是在 T-SQL 中进行转换。如果在 T-SQL 这端无法改写或存在修改后的性能问题,那么可以尝试在 PostgreSQL 中进行修改。 \n- **代码可读性**:对于要修改的 SQL 语句,可能有好几种的改写方法。简单、高效、可读性好永远都是首选。例如,大部分情况下,使用 Case 语句比使用..Then 更容易理解。\n\n#### **3.简单代码转换**\n\n归于这一类的代码转换,其特点就是修改简单,但其数量常常在评估报告中列出的所有不支持特性的 SQL 语句中占绝大部分。此类代码转换工作一般而言只需屏蔽相关选项、注释整条语句或简单修改即可。如此修改的原因,是缘于 PostgreSQL 和 SQL Server 的两者间的特性差异或 Babelfish 的限制。SQL Server 中的某些选项或操作,在 Babelfish 不支持且不会对功能执行有影响,可以直接忽略。虽然这类 SQL 语句改写简单,但能达到了相同的效果。\n\n演示之前,让我们看看接下来都会使用到两张表的结构:\n```\ncreate table dept(\n deptno int NOT NULL PRIMARY KEY,\n dname varchar(14),\n loc varchar(13)\n) \n\ncreate table employees (\n empno int NOT NULL PRIMARY KEY,\n ename varchar(10), \n job varchar(9), \n mgr int, \n hiredate datetime, \n sal money, \n comm money, \n deptno int\n)\n```\n- **ALTER TABLE..CHECK CONSTRAINT**\n\n原语句:\n```\nALTER TABLE [dbo].[employees] WITH CHECK ADD CONSTRAINT [FK_DEPT] FOREIGN KEY([deptno])\nREFERENCES [dbo].[dept] ([deptno])\nGO\nALTER TABLE [dbo].[Employees] CHECK CONSTRAINT [FK_DEPT]\nGO\n```\n修改后语句:\n```\nALTER TABLE [dbo].[employees] ADD CONSTRAINT [FK_DEPT] FOREIGN KEY([deptno])\nREFERENCES [dbo].[dept] ([deptno])\nGO\n```\n说明:\n\n1. 在 Babelfish 中不支持 CHECK CONSTRAINT 语句启用表的约束,ALTER 表添加约束后会自动启用约束。\n\n2. 在 Babelfish 中添加约束时不支持 WITH CHECK/NOHECK 选项对已有数据进行约束检查。\n\n3. 这种不支持的 ALTER TABLE 特性的语句是迁移过程中最常见的,一般是修改后在 Babelfish 上新建表和约束,再导入表的数据,表的约束会自动检查导入的数据,保证数据约束有效。\n\n- **ALTER ROLE..**\n\n原语句:\n```\nALTER ROLE [???] ADD MEMBER [NT AUTHORITY\\SYSTEM]\nGO\n```\n修改后语句\n```\n/* ALTER ROLE [???] ADD MEMBER [NT AUTHORITY\\SYSTEM]\nGO */\n```\n说明:\n\n1. 目前 Babelfish 只支持用户数据库中的 dbo 用户,您不能创建具有较低权限的用户,例如对某些表的只读权限。\n\n2. 大部分此类语句都是用户以操作系统权限登陆 SQL Server 源后倒出的 DDL 语句,可以直接注释屏蔽语句。\n\n- **ALTER DATABASE..**\n原语句:\n```\nALTER DATABASE [???] SET RECOVERY FULL \nGO\n```\n修改后语句:\n```\nALTER DATABASE [???] SET RECOVERY FULL \nGO\n```\n说明:\n\nBabelfish 不支持 ALTER DATABASE 语法,Aurora PostgreSQL 是一个全托管型数据库,会限制一些数据库修改语句,这些语句可以直接注释屏蔽\n\n- **ALTER AUTHORIZATION ON object**\n原语句:\n```\nALTER AUTHORIZATION ON [dbo].[employees] TO SCHEMA OWNER \nGO\n```\n改后语句:\n```\n/* ALTER AUTHORIZATION ON [dbo].[employees] TO SCHEMA OWNER \nGO */\n```\n说明:\nBabelfish 不支持 AUTHORIZATION 的创建、修改和删除,可以直接注释屏蔽。\n\n- **EXEC sys.sp_addextendedproperty**\n原语句:\n```\nEXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'编号' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'dept', @level2type=N'COLUMN',@level2name=N'deptno'\nGO\n```\n改后语句(在PostgreSQL端修改):\n```\nCOMMENT ON COLUMN dept.deptno IS '编号';\n```\n说明:\n\nBabelfish 不支持使用系统存储过程 sp_addextendedproperty 为字段增加说明,可以直接注释屏蔽此 SQL 语句,并连接到 PostgreSQL 端使用 comment 增加字段说明。\n\n- **OBJECTPROPERTY**\n原语句\n```\nselect name from sysobjects where objectproperty(id, N'IsTable') = 1 and name not like N'#%%' order by name\nselect * from sysobjects where id = object_id(N'temp_tableSpaceInfo') AND objectproperty(id, N'IsUserTable') = 1\n```\n改后语句:\n```\nselect name from sysobjects where xtype in ('U','IT','S') and name not like N'#%%' order by name\nselect * from sysobjects where id = object_id(N'temp_tableSpaceInfo') AND xtype='U'\n```\n说明:\n\nBabelfish 不支持内置的元数据函数 OBJECTPROPERTYEX,可根据 SQL 语义进行适当改写\n\n- **SET ROWCOUNT**\n原语句:\n```\nCREATE PROCEDURE [dbo].[P_Rowcount]\n@id int\nas\nset nocount on\nset rowcount @id \nbegin\nselect * from employees order by empno\nend\nGO\n```\n改后语句:\n```\nCREATE PROCEDURE [dbo].[P_Rowcount]\n@id int\nas\nset nocount on\nbegin\nselect top (@id) * from employees order by empno\nend\nGO\n```\n第二种修改后:\n```\nCREATE PROCEDURE [dbo].[P_Rowcount]\n@id int\nas\nset nocount on\nbegin\nselect * from employees order by empno offset 0 rows fetch first @id rows only;\nend\nGO\n```\n说明:\n\nBabelfish 不支持 SET ROWCOUNT 语句来返回指定的行数,可根据 SQL 语义进行适当改写。从示例中我们看到可以有多种的改写方法,在业务复杂的场景下应从代码的可读性和性能影响方面做选择。\n\n- **CURRENT OF**\n原语句:\n```\nCREATE PROCEDURE [dbo].[P_CurrentOf] AS\nBEGIN\n DECLARE @empno int\n DECLARE NoResponce CURSOR FOR\n SELECT empno FROM employees;\n OPEN NoResponce;\n FETCH NEXT FROM NoResponce INTO @empno;\n DELETE FROM employees WHERE CURRENT OF NoResponce;\nEND\nGO\n```\n改后语句:\n```\nCREATE PROCEDURE [dbo].[P_CurrentOf] AS\nBEGIN\n DECLARE @empno int\n DECLARE NoResponce CURSOR FOR\n SELECT empno FROM employees;\n OPEN NoResponce;\n FETCH NEXT FROM NoResponce INTO @empno;\n DELETE FROM employees WHERE empno = @empno;\nEND\nGO\n```\n备注:\n\nWhere Current Of语句允许您更新或者是删除最后由 cursor 取的记录,Babelfish 不支持 Current Of 语句,可根据 SQL 语句上下文语义选取变量\n\n- **IDENTITY**\n原语句:\n```\nSELECT IDENTITY(INT,1,1) AS rowid,* INTO #tmp\nFROM employees\nORDER BY empno\n```\n改后语句:\n```\nSELECT row_number() over () as rowid, * INTO #tmp\nFROM employees\nORDER BY empno\n```\n说明:\n\nBabelfish 不支持 IDENTITY 函数,用于在带有 INTO 子句的 SELECT 语句中将标识列插入到新表中,可使用 row_number() over ()方式改写。\n\n#### **4. 复杂代码转换**\n相对于前面介绍简单代码转换,接下来的这些 SQL 语句会复杂一些,修改内容也比较多。同时,您还需要仔细地审查 SQL 语句中上下文之间的关系,以确保修改后的语句和原语句执行得到相同的效果。\n\n- **MERGE**\n在这个案例演示之前,创建两张 MERGE 使用的源表和目标表\n```\ncreate table source\n(\n id int not null primary key ,\n country varchar(20) null,\n city varchar(20)\n);\n\ninsert into source\n (id, country, city)\n VALUES\n (1, 'RUSSIA', 'MOSCOW'),\n (2, 'FRANCE', 'PARIS'),\n (3, 'ENGLAND', 'LONDON'),\n (4, 'USA', 'NEW YORK'),\n (5, 'GERMANY', 'BERLIN'),\n (6, 'BRAZIL', 'BRASILIA');\n\ncreate table target\n(\n id int not null primary key ,\n country varchar(20) null,\n city varchar(20)\n);\n\ninsert into target\n (id, country, city)\n VALUES\n (1, 'JAPAN', 'TOKYO'),\n (4, 'USA', 'DENVER'),\n (7, 'CHINA', 'BEI JING');\n```\n原语句:\n```\nMERGE INTO target AS C2\nUSING source AS C1 \nON C2.id = C1.id\nWHEN MATCHED\n THEN UPDATE \n SET\n C2.country = C1.country,\n C2.city = c1.city\nWHEN NOT MATCHED\n THEN INSERT (id, country, city)\n VALUES (C1.id, C1.country, C1.city);\n```\n修改后语句:\n```\nbegin\nupdate target set country = C1.country, city = C1.city from (select id, country, city from source) C1 where target.id = C1.id;\ninsert into target (id, country, city) select * from source as C1 where not exists (select id from target where id = C1.id);\nend\ngo\n```\n第二种修改(在 PostgreSQL 端修改):\n```\nwith upsert as\n(update target c2 set country=c1.country, city=c1.city \n from source c1 where c1.id=c2.id\n RETURNING c2.*\n)\ninsert into target select a.id, a.country, a.city \nfrom source a where a.id not in (select b.id from upsert b);\n```\n第三种修改(在 PostgreSQL 端修改):\n```\ninsert into target (id,country,city) select id,country,city \nfrom source\non conflict (id)\ndo update set country=excluded.country,city=excluded.city;\n```\n说明:\n\n1. MERGE 是常用的一种数据合并更新语句,Babelfish 不支持MERGE语句,一般来说可根据 SQL 语义在 T-SQL 中拆分成多个 DML 语句,也可以在 PostgreSQL 端进行等价的改写。\n\n2. PostgreSQL 目前还不支持 MERGE 语句,可以使用 UPSET 或CONFLICT语句实现,INSERT ON CONFLICT 的执行开销要小于 UPDATE \n语句。\n\n- **FULLTEXT 全文搜索**\nBabelfish 不支持 SQL Server 的全文搜索,不支持以下的语句及系统存储过程\n```\nCREATE、ALTER、DROP FULLTEXT CATALOG\nCREATE、ALTER、DROP FULLTEXT INDEX\nCREATE、ALTER、DROP FULLTEXT STOPLIST\nexec sp_fulltext_database 'enable';\n```\nAmazon Aurora PostgreSQL 兼容版本增加了对 pg_bigm 扩展程序的支持。pg_bigm 扩展程序在 PostgreSQL 中提供有全文搜索功能。此扩展程序允许用户创建 2-gram(双组),以提高全文搜索速度。以下案例演示如何在 PostgreSQL 端通过扩展启用全文搜索功能:\n```\nset search_path=dbo;\ncreate extension pg_bigm;\n\nCREATE TABLE fulltext_doc (doc text);\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 成本优化');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 性能优化');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 提升使用体验');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 中提供 2-gram 全文搜索功能的工具');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 中提供 3-gram 全文搜索功能的工具');\n\nCREATE INDEX fulltext_doc_idx ON fulltext_doc USING gin (doc gin_bigm_ops);\nalter table fulltext_doc owner to dbo;\n```\n全文搜索设置成功后可以在TDS端口通过 T-SQL 调用:\n![image.png](https://dev-media.amazoncloud.cn/3beb8ef80e0341b1bcad03376e34bf75_image.png)\n\n- **SWITCHOFFSET**\n\n原语句:\n```\nSELECT CAST(SWITCHOFFSET(TODATETIMEOFFSET(SYSUTCDATETIME(),'+00:00'),'+08:00') AS DATETIME)\n```\n修改后语句(在 PostgreSQL 端创建自定义函数):\n```\nCREATE OR REPLACE FUNCTION dbo.f_get_cst()\nRETURNS sys.datetime AS $$ \n BEGIN\n RETURN cast(timezone('Asia/Shanghai',now()) as sys.datetime);\nEND;\n$$ LANGUAGE plpgsql;\n```\n说明:\n\nBabelfish 不支持 SWITCHOFFSET 和 TODATETIMEOFFSET 之类的时区偏移量内置函数,可以在 PostgreSQL 端创建自定义函数并在 TDS 端口通过 T-SQL 调用来实现相同功能\n\n- **XML 方法**\n在本案例演示之前,创建一张和 xml 解析相关的表:\n```\ncreate table t_xml_test (\n id int,\n country nvarchar(max),\n industry nvarchar(max)\n); \n\ninsert t_xml_test values(1, 'China', 'Manufacturing and foreign trade business');\ninsert t_xml_test values(2, 'USA', 'Financial and Bioindustry');\ninsert t_xml_test values(3, 'Russia', 'Resource export');\n```\n原语句:\n```\ncreate procedure p_xml_test\n @xml xml\nas\nbegin \n set nocount on\n select * from t_xml_test\n where id in (select imgXML.Item.value('id[1]','int') from @xml.nodes('/root/country') as imgXML(Item)); \n set nocount off\nend\ngo\n```\n修改后语句(首先在 PostgreSQL 端创建自定义函数解析XML):\n```\nCREATE OR REPLACE FUNCTION xmlQueryID(in_xml xml) \nRETURNS TABLE (id text) \nAS $$\nDECLARE\nBEGIN\n RETURN QUERY\n select * from (\n WITH xmldata(data) AS (VALUES (in_xml::xml))\n SELECT xmltable.*\n FROM XMLTABLE('/root/country' PASSING (SELECT data FROM xmldata) COLUMNS id text)) as foo;\nEND;\n$$ LANGUAGE plpgsql;\n```\n连接 TDS 端口在 T-SQL 中修改 SQL 语句并调用 PostgreSQL 端创建的自定义函数:\n```\ncreate procedure p_xml_test\n @xml xml\nas\nbegin \n set nocount on \n select * from t_xml_test\n where id in (select * from xmlQueryID(@xml)) ;\n set nocount off\nend\ngo\n```\n在 T-SQL 中调用存储过程测试,查询结果显示 xml 解析正常,数据显示正确:\n![image.png](https://dev-media.amazoncloud.cn/2c744fe857ee4c9a8ade7cd01522cd80_image.png)\n\n说明:Babelfish 不支持解析XML数据的方法,包括 VALUES、XML.NODES 和其他方法,可以在 PostgreSQL 端创建自定义函数并在 TDS 端口通过 T-SQL 调用来完成XML数据的解析工作。\n\n#### **总结**\n通过前面的案例介绍,我们为您展示了使用 **Babelfish** 迁移 SQL Server 时一些最常见的不支持特性SQL的转换方法。当前,Babelfish for PostgreSQL 项目持续向前发展,版本在不断更新。每个新的版本都会添加一些重要的功能,包括增加语法的兼容和 SQL Server 原生功能的支持。建议您在规划和实施 SQL Server 迁移时经常检查 Babelfish 的特性支持说明,使用最新的特性支持来完成代码的转换。\n\n同时,在2021年10月28日,亚马逊云科技正式宣布推出 **Babelfish for PostgreSQL** 开源项目。此举使用户能够在自己的 PostgreSQL 服务器上利用 Babelfish。\n\n更多更详细的 SQL Server 迁移到 Amazon Aurora PostgreSQL 代码转换请参考官方**迁移手册**,但请注意,这些转换都是在 PostgreSQL 端改写,需要考虑如何在T-SQL侧调用。\n\n了解更多 Babelfish 特性支持的信息:[https://babelfishpg.org/docs/usage/limitations-of-babelfish/](https://babelfishpg.org/docs/usage/limitations-of-babelfish/ )\n\n了解更多 Babelfish for PostgreSQL 的信息:[https://aws.amazon.com/cn/about-aws/whats-new/2021/10/babelfish-postgresql-open-source-project/](https://aws.amazon.com/cn/about-aws/whats-new/2021/10/babelfish-postgresql-open-source-project/)\n\n了解更多迁移手册内容的信息:[https://aws.amazon.com/cn/dms/resources/](https://aws.amazon.com/cn/dms/resources/ ) \n\n##### **本篇作者**\n**唐晓华**\n亚马逊云科技数据库解决方案技术专家,二十余年数据库行业经验,负责基于亚马逊云计算数据库产品的技术咨询与解决方案工作。专注于云上关系型数据库架构设计、测试、运维、优化及迁移等工作。\n\n[阅读原文](https://github.com/yuhuiaws/ML-study/tree/main/)\n\n","render":"<h4><a id=\"_0\"></a><strong>前言</strong></h4>\n<p>尽管毫无疑问,传统商业许可数据库拥有丰富的功能和完善的支持,但其严格的定价模式、繁琐的许可条款以及较高的总体拥有成本(<strong>TCO</strong>)使得企业希望采用成本更低的开源解决方案。某些方面,开源数据库以更低的成本提供了相同甚至更好的功能。从商业数据库迁移到开源数据库可为企业在许可和支持方面节省大量成本。</p>\n<p><strong>PostgreSQL</strong> 是企业级的,功能丰富的开源数据库系统,它高度可靠且性能卓越,非常适合实时和任务关键型应用程序。<strong>Amazon Aurora</strong> 是一种关系数据库服务,既有高端商用数据库的高速度和可用性,也有开源数据库的简单性和成本效益。Aurora 与 MySQL 和 PostgreSQL 完全兼容,使现有应用程序和工具无需修改即可运行。与典型的 PostgreSQL 数据库相比,它将性能提高了三倍,并且增加了可扩展性、持久性和安全性。</p>\n<p>从传统的 <strong>SQL Server</strong> 数据库迁移可能非常耗时且需耗费大量资源,任何迁移都涉及三个主要步骤:移动架构、迁移数据和修改客户端应用程序。正如下图中我们所见:迁移数据库时,您可以使用 <strong>Amazon Schema Conversion Tool(SCT)</strong> 配合 <strong>Amazon Database Migration Service (DMS)</strong> 自动迁移数据库架构和数据,但迁移应用程序本身时,通常需要完成更多的工作,包括重写与数据库交互的应用程序代码,将 T-SQL 代码迁移到 PL/pgSQL 中,这是复杂、耗时且有风险的。</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/cf75c1a1c18447c98f932683a84544af_image.png\" alt=\"image.png\" /></p>\n<p><strong>Babelfish for Aurora PostgreSQL</strong> 是 Amazon Aurora PostgreSQL 兼容版本的一项新功能,可以理解 Microsoft SQL Server 专有的 SQL 语言 T-SQL,并支持相同的通信协议,因此,修改 SQL Server 上运行的应用程序并将其移动到 Aurora 所需的工作量将减少,从而可实现更快、风险更低且更具成本效益的迁移。</p>\n<p>Babelfish 通过支持 Aurora PostgreSQL 的 Microsoft SQL Server 数据类型、语法和函数来支持 T-SQL 和 SQL Server 行为。但请注意,Babelfish 并不提供对 T-SQL 的100%完整支持,仍然有一些<strong>差异和限制</strong>,某些情况下需要做手工的代码转换。</p>\n<p>本文将列举并演示一些高频及常见的典型代码转换案例,帮助您更高效快速地完成迁移工作。</p>\n<p>了解更多Babelfish for Aurora PostgreSQL信息:<br />\n<a href=\"https://aws.amazon.com/cn/rds/aurora/babelfish/\" target=\"_blank\">https://aws.amazon.com/cn/rds/aurora/babelfish/</a></p>\n<p>了解更多Babelfish 的 Aurora PostgreSQL 与 SQL Server 间的区别信息:<br />\n<a href=\"https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-compatibility.html\" target=\"_blank\">https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-compatibility.html</a></p>\n<h3><a id=\"_23\"></a><strong>环境准备</strong></h3>\n<p>在开始我们的演示之前,假设在您的工作环境,已有一个准备迁移的 SQL Server 源库,那么除此之外,您还需要设置好以下相关的组件:</p>\n<ul>\n<li>\n<p><strong>Babelfish Compass</strong><br />\n这是一个开源的 SQL Server 迁移到 Babelfish 的语法评估工具,可以在 <strong>GitHub</strong> 上下载。它能在 Windows 和 Linux 平台下运行,需要 Java 环境支持,当前的版本是 v2022-04。</p>\n</li>\n<li>\n<p><strong>Babelfish for Aurora PostgreSQL</strong><br />\nBabelfish 从2021年秋发布第一个版本1.0.0开始,目前版本已经更新到1.2.1,对应的 Aurora PostgreSQL 版本是13.6。您可以根据<strong>官方文档</strong>说明来操作,只需简单几步即可创建一个 Babelfish for Aurora PostgreSQL 集群环境。配置过程中需要注意的就是数据库迁移模式的选择,还有如果有中文数据的话那么在排序规则中请选择“chinese_prc_ci_as”。<br />\n<img src=\"https://dev-media.amazoncloud.cn/79a757fb8e644d86b2ba8dc2caeede62_image.png\" alt=\"image.png\" /></p>\n</li>\n</ul>\n<p>到目前为止,一个包含 SQL Server 源和 Aurora PostgreSQL 目标以及迁移评估工具的环境已经准备好。接下来,请参考这个博客的内容,您只需要花短短的几分钟就能<strong>生成一个 Babelfish 迁移评估报告</strong>。</p>\n<p>了解更多 GitHub 信息:<br />\n<a href=\"https://github.com/babelfish-for-postgresql/babelfish_compass\" target=\"_blank\">https://github.com/babelfish-for-postgresql/babelfish_compass</a></p>\n<p>了解更多 官方文档 信息: <a href=\"https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-create.html\" target=\"_blank\">https://docs.amazonaws.cn/AmazonRDS/latest/AuroraUserGuide/babelfish-create.html</a></p>\n<p>生成一个 Babelfish 迁移评估报告请参考:<br />\n<a href=\"https://aws.amazon.com/cn/blogs/database/migrate-from-sql-server-to-amazon-aurora-using-babelfish/\" target=\"_blank\">https://aws.amazon.com/cn/blogs/database/migrate-from-sql-server-to-amazon-aurora-using-babelfish/</a></p>\n<h3><a id=\"_43\"></a><strong>代码转换</strong></h3>\n<h4><a id=\"1__44\"></a><strong>1. 转换评估</strong></h4>\n<p>Babelfish Compass 工具生成的评估报告是评估迁移工作内容和工作量的指引,您可以根据其中列出的需要修改的项目,逐一编写SQL代码转换内容。</p>\n<p>评估报告的 Summary 章节列出了迁移SQL Server 源到 Babelfish 目标的 T-SQL 的语法特性兼容统计,包括支持、不支持、语义审查、手动审查及可忽略项。其中最关键的是不支持特性的内容,这些含有不支持特性的 SQL 语句,如果不作修改,在 Babelfish for Aurora PostgreSQL 环境中大部分执行会报错:“<strong>‘???’ is not currently supported in Babelfish</strong>”,而其他的一些 SQL 语句虽然没有报错,但不会真正生效。</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/f967a35d0d3846eb9876b183b6f809f5_image.png\" alt=\"image.png\" /></p>\n<p>在评估报告中我们可以查看这些不支持特性的 SQL 分类统计,下图中的评估报告列出了每一类不支持特性的 SQL 语句,它显示了我们的案例所用的DDL脚本在 Babelfish 中不支持的特性主要有对表增加约束语句,Merge 语句、修改数据库、修改角色、执行某些系统存储过程等。</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/0a5dfd0bc3a54c479d7b9af62705bd08_image.png\" alt=\"image.png\" /></p>\n<h4><a id=\"2_55\"></a><strong>2.转换原则</strong></h4>\n<p><strong>Babelfish 为 Aurora PostgreSQL 数据库集群提供了一个额外的端点,使其能够了解 SQL Server 线路级协议和常用的 SQL Server 语句</strong>。迁移之后,您仍然可以使用相同的 T-SQL 开发工具和驱动,连接到TDS端口完成相关的开发。</p>\n<p>您也可以使用原生 PostgreSQL 连接在 PostgreSQL 这一端做开发,再从 T-SQL 这端进行调用。这一种兼容模式,能帮助我们解决大部分的 Babelfish 对T-SQL的兼容性问题。</p>\n<ul>\n<li><strong>选择转换模式</strong>:如上所述,对于部分不支持的 SQL 语句,我们可以选择在 T-SQL 中进行改写,也可以在 PostgreSQL 中修改再从 T-SQL 中调用。转换的原则是根据应用的连接开发模式而定,例如 .net 应用连接到 TDS 端开发,那么首选转换模式就是在 T-SQL 中进行转换。如果在 T-SQL 这端无法改写或存在修改后的性能问题,那么可以尝试在 PostgreSQL 中进行修改。</li>\n<li><strong>代码可读性</strong>:对于要修改的 SQL 语句,可能有好几种的改写方法。简单、高效、可读性好永远都是首选。例如,大部分情况下,使用 Case 语句比使用…Then 更容易理解。</li>\n</ul>\n<h4><a id=\"3_64\"></a><strong>3.简单代码转换</strong></h4>\n<p>归于这一类的代码转换,其特点就是修改简单,但其数量常常在评估报告中列出的所有不支持特性的 SQL 语句中占绝大部分。此类代码转换工作一般而言只需屏蔽相关选项、注释整条语句或简单修改即可。如此修改的原因,是缘于 PostgreSQL 和 SQL Server 的两者间的特性差异或 Babelfish 的限制。SQL Server 中的某些选项或操作,在 Babelfish 不支持且不会对功能执行有影响,可以直接忽略。虽然这类 SQL 语句改写简单,但能达到了相同的效果。</p>\n<p>演示之前,让我们看看接下来都会使用到两张表的结构:</p>\n<pre><code class=\"lang-\">create table dept(\n deptno int NOT NULL PRIMARY KEY,\n dname varchar(14),\n loc varchar(13)\n) \n\ncreate table employees (\n empno int NOT NULL PRIMARY KEY,\n ename varchar(10), \n job varchar(9), \n mgr int, \n hiredate datetime, \n sal money, \n comm money, \n deptno int\n)\n</code></pre>\n<ul>\n<li><strong>ALTER TABLE…CHECK CONSTRAINT</strong></li>\n</ul>\n<p>原语句:</p>\n<pre><code class=\"lang-\">ALTER TABLE [dbo].[employees] WITH CHECK ADD CONSTRAINT [FK_DEPT] FOREIGN KEY([deptno])\nREFERENCES [dbo].[dept] ([deptno])\nGO\nALTER TABLE [dbo].[Employees] CHECK CONSTRAINT [FK_DEPT]\nGO\n</code></pre>\n<p>修改后语句:</p>\n<pre><code class=\"lang-\">ALTER TABLE [dbo].[employees] ADD CONSTRAINT [FK_DEPT] FOREIGN KEY([deptno])\nREFERENCES [dbo].[dept] ([deptno])\nGO\n</code></pre>\n<p>说明:</p>\n<ol>\n<li>\n<p>在 Babelfish 中不支持 CHECK CONSTRAINT 语句启用表的约束,ALTER 表添加约束后会自动启用约束。</p>\n</li>\n<li>\n<p>在 Babelfish 中添加约束时不支持 WITH CHECK/NOHECK 选项对已有数据进行约束检查。</p>\n</li>\n<li>\n<p>这种不支持的 ALTER TABLE 特性的语句是迁移过程中最常见的,一般是修改后在 Babelfish 上新建表和约束,再导入表的数据,表的约束会自动检查导入的数据,保证数据约束有效。</p>\n</li>\n</ol>\n<ul>\n<li><strong>ALTER ROLE…</strong></li>\n</ul>\n<p>原语句:</p>\n<pre><code class=\"lang-\">ALTER ROLE [???] ADD MEMBER [NT AUTHORITY\\SYSTEM]\nGO\n</code></pre>\n<p>修改后语句</p>\n<pre><code class=\"lang-\">/* ALTER ROLE [???] ADD MEMBER [NT AUTHORITY\\SYSTEM]\nGO */\n</code></pre>\n<p>说明:</p>\n<ol>\n<li>\n<p>目前 Babelfish 只支持用户数据库中的 dbo 用户,您不能创建具有较低权限的用户,例如对某些表的只读权限。</p>\n</li>\n<li>\n<p>大部分此类语句都是用户以操作系统权限登陆 SQL Server 源后倒出的 DDL 语句,可以直接注释屏蔽语句。</p>\n</li>\n</ol>\n<ul>\n<li><strong>ALTER DATABASE…</strong><br />\n原语句:</li>\n</ul>\n<pre><code class=\"lang-\">ALTER DATABASE [???] SET RECOVERY FULL \nGO\n</code></pre>\n<p>修改后语句:</p>\n<pre><code class=\"lang-\">ALTER DATABASE [???] SET RECOVERY FULL \nGO\n</code></pre>\n<p>说明:</p>\n<p>Babelfish 不支持 ALTER DATABASE 语法,Aurora PostgreSQL 是一个全托管型数据库,会限制一些数据库修改语句,这些语句可以直接注释屏蔽</p>\n<ul>\n<li><strong>ALTER AUTHORIZATION ON object</strong><br />\n原语句:</li>\n</ul>\n<pre><code class=\"lang-\">ALTER AUTHORIZATION ON [dbo].[employees] TO SCHEMA OWNER \nGO\n</code></pre>\n<p>改后语句:</p>\n<pre><code class=\"lang-\">/* ALTER AUTHORIZATION ON [dbo].[employees] TO SCHEMA OWNER \nGO */\n</code></pre>\n<p>说明:<br />\nBabelfish 不支持 AUTHORIZATION 的创建、修改和删除,可以直接注释屏蔽。</p>\n<ul>\n<li><strong>EXEC sys.sp_addextendedproperty</strong><br />\n原语句:</li>\n</ul>\n<pre><code class=\"lang-\">EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'编号' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'dept', @level2type=N'COLUMN',@level2name=N'deptno'\nGO\n</code></pre>\n<p>改后语句(在PostgreSQL端修改):</p>\n<pre><code class=\"lang-\">COMMENT ON COLUMN dept.deptno IS '编号';\n</code></pre>\n<p>说明:</p>\n<p>Babelfish 不支持使用系统存储过程 sp_addextendedproperty 为字段增加说明,可以直接注释屏蔽此 SQL 语句,并连接到 PostgreSQL 端使用 comment 增加字段说明。</p>\n<ul>\n<li><strong>OBJECTPROPERTY</strong><br />\n原语句</li>\n</ul>\n<pre><code class=\"lang-\">select name from sysobjects where objectproperty(id, N'IsTable') = 1 and name not like N'#%%' order by name\nselect * from sysobjects where id = object_id(N'temp_tableSpaceInfo') AND objectproperty(id, N'IsUserTable') = 1\n</code></pre>\n<p>改后语句:</p>\n<pre><code class=\"lang-\">select name from sysobjects where xtype in ('U','IT','S') and name not like N'#%%' order by name\nselect * from sysobjects where id = object_id(N'temp_tableSpaceInfo') AND xtype='U'\n</code></pre>\n<p>说明:</p>\n<p>Babelfish 不支持内置的元数据函数 OBJECTPROPERTYEX,可根据 SQL 语义进行适当改写</p>\n<ul>\n<li><strong>SET ROWCOUNT</strong><br />\n原语句:</li>\n</ul>\n<pre><code class=\"lang-\">CREATE PROCEDURE [dbo].[P_Rowcount]\n@id int\nas\nset nocount on\nset rowcount @id \nbegin\nselect * from employees order by empno\nend\nGO\n</code></pre>\n<p>改后语句:</p>\n<pre><code class=\"lang-\">CREATE PROCEDURE [dbo].[P_Rowcount]\n@id int\nas\nset nocount on\nbegin\nselect top (@id) * from employees order by empno\nend\nGO\n</code></pre>\n<p>第二种修改后:</p>\n<pre><code class=\"lang-\">CREATE PROCEDURE [dbo].[P_Rowcount]\n@id int\nas\nset nocount on\nbegin\nselect * from employees order by empno offset 0 rows fetch first @id rows only;\nend\nGO\n</code></pre>\n<p>说明:</p>\n<p>Babelfish 不支持 SET ROWCOUNT 语句来返回指定的行数,可根据 SQL 语义进行适当改写。从示例中我们看到可以有多种的改写方法,在业务复杂的场景下应从代码的可读性和性能影响方面做选择。</p>\n<ul>\n<li><strong>CURRENT OF</strong><br />\n原语句:</li>\n</ul>\n<pre><code class=\"lang-\">CREATE PROCEDURE [dbo].[P_CurrentOf] AS\nBEGIN\n DECLARE @empno int\n DECLARE NoResponce CURSOR FOR\n SELECT empno FROM employees;\n OPEN NoResponce;\n FETCH NEXT FROM NoResponce INTO @empno;\n DELETE FROM employees WHERE CURRENT OF NoResponce;\nEND\nGO\n</code></pre>\n<p>改后语句:</p>\n<pre><code class=\"lang-\">CREATE PROCEDURE [dbo].[P_CurrentOf] AS\nBEGIN\n DECLARE @empno int\n DECLARE NoResponce CURSOR FOR\n SELECT empno FROM employees;\n OPEN NoResponce;\n FETCH NEXT FROM NoResponce INTO @empno;\n DELETE FROM employees WHERE empno = @empno;\nEND\nGO\n</code></pre>\n<p>备注:</p>\n<p>Where Current Of语句允许您更新或者是删除最后由 cursor 取的记录,Babelfish 不支持 Current Of 语句,可根据 SQL 语句上下文语义选取变量</p>\n<ul>\n<li><strong>IDENTITY</strong><br />\n原语句:</li>\n</ul>\n<pre><code class=\"lang-\">SELECT IDENTITY(INT,1,1) AS rowid,* INTO #tmp\nFROM employees\nORDER BY empno\n</code></pre>\n<p>改后语句:</p>\n<pre><code class=\"lang-\">SELECT row_number() over () as rowid, * INTO #tmp\nFROM employees\nORDER BY empno\n</code></pre>\n<p>说明:</p>\n<p>Babelfish 不支持 IDENTITY 函数,用于在带有 INTO 子句的 SELECT 语句中将标识列插入到新表中,可使用 row_number() over ()方式改写。</p>\n<h4><a id=\"4__274\"></a><strong>4. 复杂代码转换</strong></h4>\n<p>相对于前面介绍简单代码转换,接下来的这些 SQL 语句会复杂一些,修改内容也比较多。同时,您还需要仔细地审查 SQL 语句中上下文之间的关系,以确保修改后的语句和原语句执行得到相同的效果。</p>\n<ul>\n<li><strong>MERGE</strong><br />\n在这个案例演示之前,创建两张 MERGE 使用的源表和目标表</li>\n</ul>\n<pre><code class=\"lang-\">create table source\n(\n id int not null primary key ,\n country varchar(20) null,\n city varchar(20)\n);\n\ninsert into source\n (id, country, city)\n VALUES\n (1, 'RUSSIA', 'MOSCOW'),\n (2, 'FRANCE', 'PARIS'),\n (3, 'ENGLAND', 'LONDON'),\n (4, 'USA', 'NEW YORK'),\n (5, 'GERMANY', 'BERLIN'),\n (6, 'BRAZIL', 'BRASILIA');\n\ncreate table target\n(\n id int not null primary key ,\n country varchar(20) null,\n city varchar(20)\n);\n\ninsert into target\n (id, country, city)\n VALUES\n (1, 'JAPAN', 'TOKYO'),\n (4, 'USA', 'DENVER'),\n (7, 'CHINA', 'BEI JING');\n</code></pre>\n<p>原语句:</p>\n<pre><code class=\"lang-\">MERGE INTO target AS C2\nUSING source AS C1 \nON C2.id = C1.id\nWHEN MATCHED\n THEN UPDATE \n SET\n C2.country = C1.country,\n C2.city = c1.city\nWHEN NOT MATCHED\n THEN INSERT (id, country, city)\n VALUES (C1.id, C1.country, C1.city);\n</code></pre>\n<p>修改后语句:</p>\n<pre><code class=\"lang-\">begin\nupdate target set country = C1.country, city = C1.city from (select id, country, city from source) C1 where target.id = C1.id;\ninsert into target (id, country, city) select * from source as C1 where not exists (select id from target where id = C1.id);\nend\ngo\n</code></pre>\n<p>第二种修改(在 PostgreSQL 端修改):</p>\n<pre><code class=\"lang-\">with upsert as\n(update target c2 set country=c1.country, city=c1.city \n from source c1 where c1.id=c2.id\n RETURNING c2.*\n)\ninsert into target select a.id, a.country, a.city \nfrom source a where a.id not in (select b.id from upsert b);\n</code></pre>\n<p>第三种修改(在 PostgreSQL 端修改):</p>\n<pre><code class=\"lang-\">insert into target (id,country,city) select id,country,city \nfrom source\non conflict (id)\ndo update set country=excluded.country,city=excluded.city;\n</code></pre>\n<p>说明:</p>\n<ol>\n<li>\n<p>MERGE 是常用的一种数据合并更新语句,Babelfish 不支持MERGE语句,一般来说可根据 SQL 语义在 T-SQL 中拆分成多个 DML 语句,也可以在 PostgreSQL 端进行等价的改写。</p>\n</li>\n<li>\n<p>PostgreSQL 目前还不支持 MERGE 语句,可以使用 UPSET 或CONFLICT语句实现,INSERT ON CONFLICT 的执行开销要小于 UPDATE<br />\n语句。</p>\n</li>\n</ol>\n<ul>\n<li><strong>FULLTEXT 全文搜索</strong><br />\nBabelfish 不支持 SQL Server 的全文搜索,不支持以下的语句及系统存储过程</li>\n</ul>\n<pre><code class=\"lang-\">CREATE、ALTER、DROP FULLTEXT CATALOG\nCREATE、ALTER、DROP FULLTEXT INDEX\nCREATE、ALTER、DROP FULLTEXT STOPLIST\nexec sp_fulltext_database 'enable';\n</code></pre>\n<p>Amazon Aurora PostgreSQL 兼容版本增加了对 pg_bigm 扩展程序的支持。pg_bigm 扩展程序在 PostgreSQL 中提供有全文搜索功能。此扩展程序允许用户创建 2-gram(双组),以提高全文搜索速度。以下案例演示如何在 PostgreSQL 端通过扩展启用全文搜索功能:</p>\n<pre><code class=\"lang-\">set search_path=dbo;\ncreate extension pg_bigm;\n\nCREATE TABLE fulltext_doc (doc text);\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 成本优化');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 性能优化');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 提升使用体验');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 中提供 2-gram 全文搜索功能的工具');\nINSERT INTO fulltext_doc VALUES('Babelfish助力SQL迁移 中提供 3-gram 全文搜索功能的工具');\n\nCREATE INDEX fulltext_doc_idx ON fulltext_doc USING gin (doc gin_bigm_ops);\nalter table fulltext_doc owner to dbo;\n</code></pre>\n<p>全文搜索设置成功后可以在TDS端口通过 T-SQL 调用:<br />\n<img src=\"https://dev-media.amazoncloud.cn/3beb8ef80e0341b1bcad03376e34bf75_image.png\" alt=\"image.png\" /></p>\n<ul>\n<li><strong>SWITCHOFFSET</strong></li>\n</ul>\n<p>原语句:</p>\n<pre><code class=\"lang-\">SELECT CAST(SWITCHOFFSET(TODATETIMEOFFSET(SYSUTCDATETIME(),'+00:00'),'+08:00') AS DATETIME)\n</code></pre>\n<p>修改后语句(在 PostgreSQL 端创建自定义函数):</p>\n<pre><code class=\"lang-\">CREATE OR REPLACE FUNCTION dbo.f_get_cst()\nRETURNS sys.datetime AS $$ \n BEGIN\n RETURN cast(timezone('Asia/Shanghai',now()) as sys.datetime);\nEND;\n$$ LANGUAGE plpgsql;\n</code></pre>\n<p>说明:</p>\n<p>Babelfish 不支持 SWITCHOFFSET 和 TODATETIMEOFFSET 之类的时区偏移量内置函数,可以在 PostgreSQL 端创建自定义函数并在 TDS 端口通过 T-SQL 调用来实现相同功能</p>\n<ul>\n<li><strong>XML 方法</strong><br />\n在本案例演示之前,创建一张和 xml 解析相关的表:</li>\n</ul>\n<pre><code class=\"lang-\">create table t_xml_test (\n id int,\n country nvarchar(max),\n industry nvarchar(max)\n); \n\ninsert t_xml_test values(1, 'China', 'Manufacturing and foreign trade business');\ninsert t_xml_test values(2, 'USA', 'Financial and Bioindustry');\ninsert t_xml_test values(3, 'Russia', 'Resource export');\n</code></pre>\n<p>原语句:</p>\n<pre><code class=\"lang-\">create procedure p_xml_test\n @xml xml\nas\nbegin \n set nocount on\n select * from t_xml_test\n where id in (select imgXML.Item.value('id[1]','int') from @xml.nodes('/root/country') as imgXML(Item)); \n set nocount off\nend\ngo\n</code></pre>\n<p>修改后语句(首先在 PostgreSQL 端创建自定义函数解析XML):</p>\n<pre><code class=\"lang-\">CREATE OR REPLACE FUNCTION xmlQueryID(in_xml xml) \nRETURNS TABLE (id text) \nAS $$\nDECLARE\nBEGIN\n RETURN QUERY\n select * from (\n WITH xmldata(data) AS (VALUES (in_xml::xml))\n SELECT xmltable.*\n FROM XMLTABLE('/root/country' PASSING (SELECT data FROM xmldata) COLUMNS id text)) as foo;\nEND;\n$$ LANGUAGE plpgsql;\n</code></pre>\n<p>连接 TDS 端口在 T-SQL 中修改 SQL 语句并调用 PostgreSQL 端创建的自定义函数:</p>\n<pre><code class=\"lang-\">create procedure p_xml_test\n @xml xml\nas\nbegin \n set nocount on \n select * from t_xml_test\n where id in (select * from xmlQueryID(@xml)) ;\n set nocount off\nend\ngo\n</code></pre>\n<p>在 T-SQL 中调用存储过程测试,查询结果显示 xml 解析正常,数据显示正确:<br />\n<img src=\"https://dev-media.amazoncloud.cn/2c744fe857ee4c9a8ade7cd01522cd80_image.png\" alt=\"image.png\" /></p>\n<p>说明:Babelfish 不支持解析XML数据的方法,包括 VALUES、XML.NODES 和其他方法,可以在 PostgreSQL 端创建自定义函数并在 TDS 端口通过 T-SQL 调用来完成XML数据的解析工作。</p>\n<h4><a id=\"_461\"></a><strong>总结</strong></h4>\n<p>通过前面的案例介绍,我们为您展示了使用 <strong>Babelfish</strong> 迁移 SQL Server 时一些最常见的不支持特性SQL的转换方法。当前,Babelfish for PostgreSQL 项目持续向前发展,版本在不断更新。每个新的版本都会添加一些重要的功能,包括增加语法的兼容和 SQL Server 原生功能的支持。建议您在规划和实施 SQL Server 迁移时经常检查 Babelfish 的特性支持说明,使用最新的特性支持来完成代码的转换。</p>\n<p>同时,在2021年10月28日,亚马逊云科技正式宣布推出 <strong>Babelfish for PostgreSQL</strong> 开源项目。此举使用户能够在自己的 PostgreSQL 服务器上利用 Babelfish。</p>\n<p>更多更详细的 SQL Server 迁移到 Amazon Aurora PostgreSQL 代码转换请参考官方<strong>迁移手册</strong>,但请注意,这些转换都是在 PostgreSQL 端改写,需要考虑如何在T-SQL侧调用。</p>\n<p>了解更多 Babelfish 特性支持的信息:<a href=\"https://babelfishpg.org/docs/usage/limitations-of-babelfish/\" target=\"_blank\">https://babelfishpg.org/docs/usage/limitations-of-babelfish/</a></p>\n<p>了解更多 Babelfish for PostgreSQL 的信息:<a href=\"https://aws.amazon.com/cn/about-aws/whats-new/2021/10/babelfish-postgresql-open-source-project/\" target=\"_blank\">https://aws.amazon.com/cn/about-aws/whats-new/2021/10/babelfish-postgresql-open-source-project/</a></p>\n<p>了解更多迁移手册内容的信息:<a href=\"https://aws.amazon.com/cn/dms/resources/\" target=\"_blank\">https://aws.amazon.com/cn/dms/resources/</a></p>\n<h5><a id=\"_474\"></a><strong>本篇作者</strong></h5>\n<p><strong>唐晓华</strong><br />\n亚马逊云科技数据库解决方案技术专家,二十余年数据库行业经验,负责基于亚马逊云计算数据库产品的技术咨询与解决方案工作。专注于云上关系型数据库架构设计、测试、运维、优化及迁移等工作。</p>\n<p><a href=\"https://github.com/yuhuiaws/ML-study/tree/main/\" target=\"_blank\">阅读原文</a></p>\n"}
目录
亚马逊云科技解决方案 基于行业客户应用场景及技术领域的解决方案
联系亚马逊云科技专家
亚马逊云科技解决方案
基于行业客户应用场景及技术领域的解决方案
联系专家
0
目录
关闭