更新大表的主表和子表的主键

时间:2008-11-20 18:53:00

标签: sql sql-server oracle migration mysql4

我有一个相当庞大的数据库,其主表包含单个列GUID(自定义GUID,如算法)作为主键,8个子表与此GUID列具有外键关系。所有表格都有大约3-8百万条记录。这些表中没有任何一个具有任何BLOB / CLOB / TEXT或任何其他奇特的数据类型,只是普通数字,变量,日期和时间戳(每个表中大约15-45列)。除主键和外键之外没有分区或其他索引。

现在,自定义GUID算法已更改,虽然没有冲突,但我希望迁移所有旧数据以使用使用新算法生成的GUID。不需要更改其他列。第一优先级是数据完整性,性能是次要的。

我能想到的一些可能的解决方案(因为你可能会注意到它们都只围绕一个想法)

  1. 添加新列ngu_id并使用新的gu_id填充;禁用约束;使用ngu_id更新子表作为gu_id; renaname ngu_id-> gu_id;重新启用约束
  2. 从子表中读取一条主记录及其相关子记录;使用新的gu_id插入到同一个表中;删除所有带有旧gu_ids的记录
  3. 掉落约束;向主表添加一个触发器,以便更新所有子表;用新的新gu_ids开始更新旧的gu_id;重新启用约束
  4. 向主表添加触发器,以便更新所有子表;用新的新gu_ids
  5. 开始更新旧的gu_id
  6. 在所有主表和子表上创建新列ngu_ids;在ngu_id列上创建外键约束;将更新触发器添加到主表以将值级联到子表;将新的gu_id值插入ngu_id列;基于gu_id删除旧的外键约束;删除gu_id列并将ngu_id重命名为gu_id;必要时重新创建约束;
  7. 如果可用,请使用on update cascade
  8. 我的问题是:

    1. 有更好的方法吗? (不能把头埋在沙子里,一定要这样做)
    2. 最合适的方法是什么? (我将在Oracle,SQL服务器和mysql4中执行此操作,因此欢迎特定于供应商的黑客攻击)
    3. 这种练习的典型失败点是什么?如何最小化?
    4. 如果你到目前为止和我在一起,谢谢,并希望你可以提供帮助:)

4 个答案:

答案 0 :(得分:2)

你的想法应该有效。第一个可能是我会用的方式。这样做时需要考虑的一些注意事项和事项:
除非您有当前备份,否则请勿这样做 我会在主表中留下这两个值。这样,如果你必须从一些旧的文书工作中找出你需要访问的记录,你就可以做到。 执行此操作时,请将数据库关闭以进行维护,并将其置于单用户模式。在做这样的事情时,你需要的最后一件事是用户在你处于中游时尝试进行更改。当然,单用户模式下的第一个动作是上述备份。当使用率最轻时,您可能应该将停机时间安排一段时间。 首先测试开发!这也应该让您了解需要多长时间才能完成生产。此外,您可以尝试几种方法来查看哪种方法最快 请务必提前告知用户数​​据库将在预定的维护时间内停止运行以及何时可以再次使用。确保时机正常。当他们计划延迟运行季度报告并且数据库不可用而且他们不知道时,这真的让人很生气。
有相当多的记录,您可能希望批量运行子表的更新(不使用级联更新的一个原因)。这比尝试通过一次更新更新500万条记录要快得多。但是,不要尝试一次更新一条记录,否则明年你仍然会在这里完成这项任务 删除所有表中GUID字段的索引,并在完成后重新创建。这应该会改善变化的表现。

答案 1 :(得分:0)

创建一个包含旧pk值和新pk值的新表。在两列上放置唯一约束,以确保您到目前为止没有破坏任何内容。

禁用约束。

对所有表运行更新,将旧值修改为新值。

启用PK,然后启用FK。

答案 2 :(得分:0)

很难说“最佳”或“最合适”的方法是什么,因为您没有在解决方案中描述您正在寻找的内容。例如,在迁移到新ID时,表是否需要可用于查询?他们是否需要同时进行修改?尽可能快地完成迁移很重要吗?最小化用于迁移的空间是否重要?

话虽如此,如果他们都符合您的要求,我宁愿选择#1优于其他想法。

任何涉及更新子表的触发器的事情似乎容易出错并且过于复杂,并且可能不会像#1那样表现良好。

假设新ID永远不会与旧ID冲突,这是否安全?如果没有,基于一次更新一个ID的解决方案将不得不担心碰撞 - 这将匆忙变得混乱。

您是否考虑过使用CREATE TABLE AS SELECT(CTAS)使用新ID填充新表?您将复制现有表,这将需要额外的空间,但它可能比更新现有表更快。这个想法是:(i)使用CTAS创建新表,用新ID代替旧表,(ii)根据新表创建索引和约束,(iii)删除旧表,(iv)重命名新表旧表名称。

答案 3 :(得分:0)

实际上,它取决于您的RDBMS。

使用Oracle,最简单的选择是使所有外键约束“延迟”(检查提交),在单个事务中执行更新,然后提交。