几年前我这样做了,我遇到了一些你想知道的问题。
假设:
- 您有一个带有 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 表的实例,它们应该是相同的,但它们的主键具有标识字段。每个子表(如客户,它链接到区域表)通过主键(身份字段)引用父表(区域) - 从一个数据库到另一个数据库不匹配。在这种情况下,明智的做法是在迁移前提前一个中断窗口,使用手动更新脚本清理这些记录。
- 禁用任何约束或外键关系
- 更改身份字段(如果它们是查找表,您可以关闭身份内容并使用手动指定的 pk 编号运行)
- 修改 Region 表以添加一个 NewID 字段,匹配它将成为什么,以及一个 OldID 字段,显示它曾经是什么
- 更新所有子表(客户)以使用 NewID 编号而不是原始编号
- 更新 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 种模式确实有意义,但除此之外,只要确保您物有所值即可。现在将是进入一个模式的好时机。