修改庞大数据库的策略

Strategies to modify huge database

我正在测试针对即将到来的重大变更的不同策略。问题是每个实验都会在 Azure 中产生一些成本。 数据庞大,在我认识这家公司之前,由于多年的修复和交易,可能会有一些不一致。

我需要更改 table 中包含数百万条记录和数十个索引的列。这将有一个很大的停机时间。

ALTER TABLE X ALTER COLUMN A1 decimal(15, 4) --原列为int

最初的想法之一(现在我知道这是不可能的是有一个辅助副本,在那里进行更改,并且在更改时完成,将主要与次要交换......零或几乎零停机时间。我指的是“实时”冗余副本,而不仅仅是“副本”

编辑: 抛出新点子:

  1. 其中一个答案中提到的变化:创建一个 table 副本(不是整个数据库,只是 table),应用一个 INSERT INTO... SELECT 并在过程结束时交换 tables。或者...尽早进行交换以最大程度地减少停机时间,以减少在post-添加来自源
  2. 的所有记录期间的延迟交易

我试过了,但需要 AGES 才能完成。此外,一些 null 和 FK 违规会使流程在处理几个小时后失败。 “恢复”可能是一个选项,但它会使每次执行的过程变慢。没有某种“恢复”,每次失败都必须从头开始

acceptable 改进可能是忽略错误(当然要创建日志)并在迁移后应用修复。但是 afaik,AzureSql(也不是 SqlServer)不提供“忽略”选项

  1. 将所有索引、约束和依赖项删除到需要修改的列,修改该列并再次应用所有索引、约束和依赖项。

这个也试过了。有些索引需要 AGES 才能完成。但是 目前看来是最好的选择 。 在数据类型更改之前应用 ROW COMPRESSION 可能会有变化,但我认为它不会改善实际情况:重新创建索引

  1. 创建一个具有目标数据类型的新列,从源列复制数据,删除旧列并重命名新列。 此策略还需要删除和重新生成索引,因此它不会提供关于 #2 的很多收益(如果有的话)。

朋友想到了一个变种,就是把列拷贝需要的索引ONLINE复制出来。同时,将源列上的所有更改触发到列复制。

对于上述任何一种策略,都可以通过提高处理能力来获得一些收益。但是,无论如何,我们考虑使用任何一种方法来增加功率,因此这对所有解决方案都是通用的

当您需要一次性更新大量行时,使用以下迁移技术可能更有效:

  • 创建新目标table
  • 使用 INSERT INTO SELECT 用正确/更新的值填充新的 table
  • rename新旧table
  • 为新 table
  • 创建索引

经过多次测试和备份,我们最终采用了以下方法:

  1. 使用所需的格式更改创建新列 [columnName_NEW]。允许 NULLS
  2. 为 INSERTS 创建触发器以使用要替换的列中的值更新新列
  3. 批量复制旧列值到新列 这个操作非常耗时。我们 运行 每天维护 window 一批(4 天 2 小时)。我们的批处理首先填充最旧行的值,我们指望触发器填充新行
  4. #3 完成后,不再允许在新列上使用 NULLS,但设置默认值以避免 INSERT 触发器崩溃
  5. 在新列上创建所有需要的索引和视图。这非常耗时,但可以在线完成
  6. 在旧列上允许 NULLS
  7. 删除插入触发器 - 现在开始停机!
  8. 将旧列重命名为 [columnName_OLD],将新列重命名为 [columnName]。这需要几秒钟的停机时间!

--> 你可以认为它终于完成了!

  1. 经过一段安全时间后,您可以备份结果并删除 [columnName_OLD] 及其所有依赖项

我选择了另一个答案,因为我认为它在大多数情况下也很有用。这个有更多的步骤,但停机时间非常短,并且在除最后一步之外的任何步骤都是可逆的。