逐步从SQL Server迁移到PostgreSQL

3

公司有许多应用程序在SQL Server上运行。数据库有点混乱。

目标是逐步从SQL Server迁移到PostgreSQL(不考虑另一个SQL Server实例)。

一个理想的情况是,新的应用程序可以连接到PostgreSQL,创建一个新的表结构,但仍然能够使用/与来自旧SQL Server的数据进行交互(一个应用程序连接两个数据库服务器不可行)。

外部数据包装器似乎不是一个选项,因为技术非常不成熟,并且在PostgreSQL的情况下,外部表是只读的。

另一个疯狂的想法是,从SQL Server实例连接到PostgreSQL,新应用程序将连接到SQL Server,但使用PostgreSQL的外部数据库。这个外部数据库(我想)将能够访问主机的数据库对象。在某一时刻,开发人员将把所有新应用程序从SQL Server切换到PostgreSQL。

当然,还有尝试同步数据的可能性。

哪种选择最好?


1
我认为没有任何办法可以像那样实现“平滑”的过渡。您需要迁移一个应用程序接着另一个,包括停机时间,在此期间将数据从 SQL Server 复制到 Postgres(当然是在使用 Postgres 测试新版本的应用程序之后)。 - user330315
1
连接两个数据库服务器的应用程序不是一个选项。问题出在哪里? - Clodoaldo Neto
3个回答

13

你提出的所有建议都会导致痛苦和迁移失败。如果您尝试使用这种方法,人们会抱怨PostgreSQL的恶劣、缓慢和不可靠。这对于想保留SQL Server但不想迁移到PostgreSQL的人来说可能是一个很好的政治策略,但不是迁移到PostgreSQL的好方法。

新版本的Pg即将推出一个读/写外部数据包装器,但最初只支持其他PostgreSQL服务器。由于需要翻译sqlstates和错误消息、搜索条件等,支持MS SQL会更加困难,因此任何包装器都无疑会相当有限并且性能较差。正如您所说,FDW支持在目前阶段还不够成熟。

尝试做这样的混合会失去许多东西:

  • 没有外键完整性强制执行

  • 每一侧的数据类型可能不完全相同,因此数据可以在一侧上是正确的,而在另一侧上则不正确。例如时间戳/日期。

  • 有效的连接需要极其复杂的外部数据包装器,所以通常情况下整个表会被获取然后本地连接。性能会非常糟糕。

  • 当您不是执行最简单的任务时,编写查询变得非常困难。函数名称不同等。

  • 您将失去或削弱许多ACID属性和/或必须使用两阶段提交,这对性能非常不利。

认真地,不要这样做。

同步数据库可能会更糟 - 除非是单向同步,否则会导致遗失更新、删除的行重新出现等问题。双向同步非常困难。

通过使它们能够在两个服务器上运行,但每次只运行一个服务器,开始为应用程序进行移动的准备。一旦您已经为Pg准备好了应用程序,开始使用迁移后的实时数据进行一些负载测试和可靠性测试。然后考虑迁移,但有计划在发现最后一分钟的问题强制您推迟时如何撤消此举。

如果您正在向应用程序添加全新的部分,并且这些部分与数据库中的其他数据没有任何交互,那么将它们存储在Pg中可能是合理的。不过这种情况相当罕见,而且当您告诉系统管理员您现在需要跨两个不同的数据库进行原子快照时,他们仍然会不喜欢你……


谢谢,这基本上总结了一切。 ;) - Magnuss

4
有趣的是,我工作的公司也做了类似的迁移(实际上,我们还在逐步淘汰最后几个 MS SQL 部分)。我们采取的基本方法是将数据库功能分别分成不同的区域或应用程序。
  • 任何全新或重写的应用程序完全使用 Postgres。这并不一定意味着应用程序层(在我们的情况下是 PHP)只连接到 Postgres,因为整个库或共享模块可能仍留在“遗留”架构中。
  • 核心配置等中央业务数据最初保留在 MS SQL 中,使用脚本定期将数据导出并导入只读的 Postgres 目标。我们使用了简单的 XML 序列化,因为发现似乎更简单的 CSV / TSV 在两个平台之间转换太麻烦了。我们在反向执行过程中也遇到了问题,因为导入过程更容易在 MS SQL 上产生破坏性的独占锁,而不是在 Postgres 上。
  • 只在一个地方写入数据的数据(例如管理面板)可以同时插入/更新旧和新的数据库。显然,这带来了手动创建不一致性的风险,但好处是两个副本都是完全相同的。它还需要注意自动生成的值,例如使用 SET IDENTITY_INSERT 强制匹配 ID。

转换单个查询相对容易,主要问题在于 CamelCase 表和列名称:SQL Server 不区分大小写但保留大小写,而 Postgres 区分大小写但将未引用的标识符折叠为小写。因此,SELECT FooID FROM ... 不仅查找名为 fooid 的列,而且将一个标记为 fooid 的字段返回给应用程序,它将期望 FooID。这需要审计大量现有应用程序代码,以便它期望下划线分隔版本,例如 foo_id,这更符合 Postgres 的行为。


0

这个问题不是问题。您可以将数据全部或部分迁移到PostgreSQL。您可以在Java、Python或其他受支持的语言中编写存储函数,并创建使用这些函数的视图。您的函数必须在每次执行时连接到MSSQL。视图名称和结构必须表示不同数据库中的MSSQL表格。在这种情况下,仅更新有点棘手,需要触发器和更多代码。通过这种方式,您可以将PostgreSQL连接到任何其他SQL / NoSQL DB供应商。它运行良好,但比在PostgreSQL中仅使用所有数据要慢。我相信,在某些情况下,从应用程序连接到两个供应商可能更简单,但这是您的选择:您有选择权。


这种方法的性能往往会非常差,因为查询规划器无法将限定词通过函数下推。想要从远程表中获取一行吗?那么你需要获取表中的所有10000行,并且扔掉9999行。 - Craig Ringer
在小表上,这不是问题。但对于大表:视图必须是调用函数和从某个本地表“lt”选择的“union all”。函数可以返回与之前调用的小增量,其中问题不相关,然后将增量推入本地表“lt”。根据定义,这个增量在下一次执行之前将是不可见的。这是一个通用的概念,我认为没有理由深入实现细节。我相信它可以适用于大多数情况,并同意“2个连接”解决方案要好得多。问题是:作者从一开始就拒绝了它。就是这样。 - Yuri Levinsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接