-2

在更新项目中,我必须执行以下操作:

将3个数据库从SQL2000移动到SQL2005,同时合并。SP 和视图中已经使用了相当多的跨数据库查询。当前计划是将每个旧数据库移动到 1 个数据库中的单独架构中。

这意味着我们还必须更改我们当前的 SP 和视图,我们现在有:

SELECT OrderId, OrderDate FROM Sales.dbo.Orders

并期望我们将不得不将其更改为

SELECT OrderId, OrderDate FROM Sales.Orders

问题是:我们如何尽可能自动化地做到这一点?

我知道 SED 和类似的更改脚本。我会欢迎有关如何对此“聪明”的提示,例如对脚本进行分区的策略、性能(大量的 INSERT INTO 行)等。

注意:我确实查看了导入/导出向导,但显然我必须在每个输出表上手动设置模式并通过 ALTER 脚本修复 SP。

4

6 回答 6

6

几年前我这样做了,我遇到了一些你想知道的问题。

假设:

  • 您有一个带有 3 个数据库 A/B/C 的 SQL 2000 数据库服务器
  • 您希望所有对象都以数据库 A 中的 SQL 2005 结束(我们将其称为目标)
  • 您希望最终摆脱数据库 B 和 C(旧的 Sources)
  • 您没有一个成熟的测试环境,您可以每天自动恢复生产数据库,并一次又一次地编写脚本,直到它正确为止。(这是最好的方法,我也采用了这种方法,但它是劳动密集型的。)

这是我的惨痛教训:

不要在同一天进行合并和 SQL 2005 更改。在您进入 2005 年之前或之后进行合并,但不要试图在一次中断中完成所有操作。这将是一个相互指责的混乱。如果是我,我会先去 2005 年,只是为了不碍事。这样,我知道任何中断都不是因为架构更改,并且这些类型的中断更容易修复。在宣布胜利并继续进行合并之前,您需要在 2005 盒子上至少有一周的最终用户活动。

提前在 Target 中构建新对象。即使它们没有在您的现场制作应用程序中被查询,也请立即构建它们。这样您就可以在其中填充虚假的测试数据以提前测试您的应用程序。是的,这意味着混合实时数据和测试数据,但坦率地说,您已经在没有网络的情况下工作了。但是,请注意身份字段,因为您最终可能会得到具有相同身份编号但目标和源数据库中的数据不同的记录冲突。

提前在 Target 中创建视图。您提到您有已经执行跨数据库查询的视图。现在将它们从 Source 复制到 Target,并告诉任何其他开发人员(报告人员、高级用户)开始引用 Target 视图。这不会加快您自己的工作,但会加快他们的工作。如果您可以验证它们是否仅命中 Target(即使 Target 视图仍指向 Source 中的表),那么它将使迁移当天的故障排除变得更容易。然后,您可以提前开始拒绝对源视图的权限。

提前同步表格。 列出需要从源中移出的所有表,并为每个表分析它是如何更新的。如果它只是被插入(未更新或删除),例如日志表,则编写一个 T-SQL 脚本以开始使其在 Target 中保持同步。在服务器上的低活动期间(例如每晚)通过 SQL 代理作业运行该脚本。这样,在上线日时,您不必推送尽可能多的记录,这意味着您的上线窗口将更小,并且您的 Target 事务日志可以保持更小。不断更新或删除的表格并不容易,您是否决定同步这些表格取决于您。我们对任何超过一百万行的表格都这样做了。

检查源数据库之间的记录冲突。听起来这个不适用于您,但我在这里指出,以防其他人进行合并并且他们正在阅读它以获取提示。如果您有多个 Source 数据库,请转储对象列表。如果您有两个具有相同名称的对象,请检查它们的架构。我曾处理过在每个数据库中都有一个 State 或 Region 表的实例,它们应该是相同的,但它们的主键具有标识字段。每个子表(如客户,它链接到区域表)通过主键(身份字段)引用父表(区域) - 从一个数据库到另一个数据库不匹配。在这种情况下,明智的做法是在迁移前提前一个中断窗口,使用手动更新脚本清理这些记录。

  1. 禁用任何约束或外键关系
  2. 更改身份字段(如果它们是查找表,您可以关闭身份内容并使用手动指定的 pk 编号运行)
  3. 修改 Region 表以添加一个 NewID 字段,匹配它将成为什么,以及一个 OldID 字段,显示它曾经是什么
  4. 更新所有子表(客户)以使用 NewID 编号而不是原始编号
  5. 更新 Region 表,使真实 ID 字段现在具有 NewID 值,而 OldID 字段具有以前的 Region 值。(你可能会搞砸一些事情,比如想念一张你不知道的儿童桌,你会想知道它曾经是什么。)

将迁移分解成碎片。列出所有数据库中的每个存储过程。如果其中任何一个可以在不移动数据的情况下移动,请先执行此操作。例如,如果您有 Source.dbo.usp_RunReport,并且它仅引用目标数据库中的表,则在第一阶段执行此操作。如果您有仅在应用程序内部使用的小型系统查找表,对客户或报告不可见,那么也将其放在第一阶段。听起来它太小了,无法打扰,但这个想法是为了减少迁移日的恐慌。您想知道的越少,您就越能排除故障。我们提前移动了每个静态查找表(州、地区、日历等)。第 1 阶段所需的工作量 - 只是移动那些小的静态表格 - 让管理层了解移动其余部分的工作量有多大,

预增长 Target 的数据文件。如果您没有使用 SQL 2005 的新即时文件初始化,那么数据文件的增长需要相当长的时间。如果您有选择,请启用即时文件初始化,然后增长数据文件以确保它们没有碎片化。如果它们只是在您迁移的那一天自然生长,它们可能会变得支离破碎。如果您不能使用即时文件初始化,您仍然需要预先增长文件,但您希望在活动较少的期间提前执行此操作以加快维护窗口。

在迁移当天,一次运行一个表,或者更小。 您希望尽可能严格地保持插入事务。插入事务越小,事务日志中所需的空间就越少。请记住,即使在简单模式下,事务日志也会随着插入语句增长。在每一轮插入之后,进行完整性检查以确保它们正常工作,并且您不会用完数据文件或 t-log 文件的驱动器空间。

更新完成后,更改源数据库的安全性。将每个非 SA 登录放入源数据库中的 dbdenydatareader 和 dbdenydatawriter 角色。这样,如果他们在连接字符串中硬编码了数据库名称,他们仍然可以登录,但他们将无法做任何事情。这也使您的故障排除变得更容易:如果应用程序或查询遇到问题,您可以考虑将他们的登录退出拒绝角色并查看它是否有效 - 如果有效,它就会失败。这样做的风险是他们可能会运行使用源数据库数据更新目标数据库的事务(从源获取客户,在目标中更新他们),这可能会导致问题。

源数据库的其他选项是:

  • 重命名它们,这样您仍然可以查询它们,但应用程序不会触及它们
  • 分离它们,但保持文件可用,以防您需要排除故障
  • 删除所有登录名,并使用新登录名访问现有数据库以防万一。然后,如果某人的只读报告完全失效,您可以通过向他们发出新的登录名并告诉他们它指的是错误的数据库来让它暂时工作。

更新完成后,在 Target 上重建索引和统计信息。如果您只是在进行连续插入,这没什么大不了的,但是如果您要合并多个数据库(例如两个已分解为该国区域的销售数据库),那么您将需要清理.

恕我直言,除非您能证明从多个模式中获益,否则请使用一种模式。最后一个只是我的两分钱,但听起来您要经历大量工作才能从 3 个数据库(每个数据库 1 个模式)到 1 个数据库(具有 3 个模式)。如果您不太确定 3 模式的事情,您可能会考虑使用 1 模式 - 否则您将在以后的道路上再次进行混乱的返工。如果您有特定的安全需求,3 种模式确实有意义,但除此之外,只要确保您物有所值即可。现在将是进入一个模式的好时机。

于 2009-03-09T12:50:59.093 回答
2

您可以试一试 Redgate SQL 比较和数据比较。他们有一个模式映射功能,应该让您将 dbo 模式映射到另一个中的销售模式,然后移动表和过程。这样您就不必弄乱 SQL 导出向导了。不过,您仍然需要重构您的其他对象。

我喜欢这两个工具。


编辑:我认为您也可以获得功能齐全的演示。


编辑:此外,他们提供 SQL Refactor,它可以“智能”重命名。分数!

于 2009-03-05T23:28:37.160 回答
1

你能有一个名为 SALES 的虚拟数据库,它有一个名为 [Orders] 的视图:

CREATE VIEW Sales.dbo.Orders
AS
SELECT OrderId, OrderDate, ...
FROM CombinedDatabase.Sales.Orders

进而

SELECT ... FROM Sales.dbo.Order

仍然可以工作。

但是,如果没有进一步的游戏,您将无法插入/更新该表。

如果你能有这样的 VIEWs 日志,它们被使用,这将使你能够修复调用它们的代码!但我想不出办法做到这一点;但是,您可以依次禁用每个测试,运行一些测试,修复任何损坏的部分,然后继续进行下一个...从而通过重构来根除它们,但在此过程中拥有一个大部分工作的应用程序。

我已经将 SED 用于这种类型的事情,但是我们的所有表和所有列都有唯一的名称,并且我们在应用程序中使用与数据库列名称匹配的变量名称 - 所以我很有信心将 xxx_yyy_ID 更改为我们的应用程序中的 aaa_bbb_ID 可以很好地工作,并且不会产生意外的副作用。

如果您有实际的列/表名称,例如“Sales”和“Orders”,我认为像 SED 这样的东西会有风险

于 2009-03-05T21:25:37.910 回答
1

好的,所以我对您的问题的基本理解是这样的:

  1. 您拥有三个不同的数据库(即 Sales、Manu、Inventory)
  2. 它们具有不同的表和过程名称(Manu 或 Inventory 中不存在 Sales 中的表/过程名称)
  3. 您希望所有三个数据库中的所有表/过程都在一个数据库中(即 SaleManInv)
  4. 每个数据库中的一些存储过程显式引用其他数据库中的表(即 Sales.dbo.lookupItem() 显式引用 Inventory.dbo.Items 表)

导出和导入表似乎不是问题,我会为 procs 做什么:

  1. 将一个 proc 从 SQL Server 2000 db 导出到 SQL Server 2005 DB,以确定是否需要删除“.dbo”。交叉引用的一部分。
  2. 将所有 procs 导出到文本文件(所有 procs 的同一文件夹)
  3. 使用带有“在文件中搜索和替换”的文本编辑器(我使用 PSPAD)并替换所有“Sales.dbo”。使用“SaleManInv.dbo.”,然后是所有“Iventory.dbo”。使用“SameManInv.dbo”。等将所有引用转换为新数据库。
  4. 然后将导出和修改的 procs 运行到您的新数据库中。

这有什么意义吗?:-)

于 2009-03-07T22:26:19.057 回答
1

我处于类似的位置,我有几个 SQL Server 2008 数据库被合并为 1。我的解决方案是使用 Integration Services 的传输服务器对象任务到一个新的目标数据库中。所有数据都与表格一起复制。之后 - 在一个非常复杂的查询中,我编写了所有存储过程/函数/视图/等的脚本。到一个文件并更改所有跨数据库引用并重新创建存储过程和其他对象。

存储过程的技巧是按顺序或 syscontraints 编写脚本,以确保最后创建内部引用其他存储过程/函数的存储过程或函数。

如果有一个我觉得可以以自动化方式处理这项任务的工具,我会立即购买它。

于 2012-10-05T15:11:13.820 回答
0

我想知道它是否是同一种数据。反正。我将创建一个名为“SourceSystem”的新列。所以当老板追上来时:

“ - 2004 年 databasesystem1 和 db2 之间的销售差异是多少”。

那你就可以回答了。然后在一两年内,如果这些问题没有出现。您可以删除该列。合并数据会删除数据的来源。

于 2009-03-05T21:47:23.567 回答