代码之家  ›  专栏  ›  技术社区  ›  shyam

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

  •  0
  • shyam  · 技术社区  · 17 年前

    我有一个相当大的数据库,其中有一个主表,其中一个列的guid(类似于自定义guid的算法)作为主键,8个子表与这个guid列有外键关系。所有的表格都有大约300-800万条记录。这些表都没有blob/clob/text或任何其他花哨的数据类型,只有普通数字、varchar、日期和时间戳(每个表中大约有15-45列)。除了主键和外键之外,没有分区或其他索引。

    现在,自定义的guid算法已经改变了,虽然没有冲突,但是我想迁移所有旧数据,以使用使用新算法生成的guid。不需要更改其他列。第一要务是数据完整性,其次是性能。

    我能想到的一些可能的解决方案是(正如你可能会注意到的那样,它们都只围绕一个想法)

    1. 添加新列ngu-id并用新的gu-id;禁用约束;使用ngu-id作为gu-id;renaname-ngu-id->gu-id;重新启用约束更新子表
    2. 从子表中读取一条主记录及其从属子记录;使用新的gu_id插入同一个表;删除所有使用旧gu_id的记录
    3. 删除约束;向主表添加触发器,以便更新所有子表;开始用新的gu_id更新旧的gu_id;重新启用约束
    4. 向主表添加触发器,以便更新所有子表;开始用新的gu-id更新旧的gu-id
    5. 在所有主表和子表上创建新的列ngu-id;在ngu-id列上创建外键约束;向主表添加更新触发器以将值级联到子表;将新的gu-id值插入到ngu-id列中;删除基于gu-id的旧外键约束;删除gu-id列并将ngu-id重命名为gu-id;如果必要的;
    6. 使用 on update cascade 如果有的话?

    我的问题是:

    1. 有更好的方法吗?(不能把我的头埋在沙子里,必须这样做)
    2. 最合适的方法是什么?(我必须在Oracle、SQL Server和MySQL4中执行此操作,因此,欢迎使用特定于供应商的黑客程序)
    3. 这种练习的典型失败点是什么?如何将其最小化?

    如果你到目前为止和我在一起,谢谢你,希望你能帮助我:)

    4 回复  |  直到 7 年前
        1
  •  2
  •   DJo 1JD    7 年前

    你的想法应该奏效。第一种可能是我使用的方式。执行此操作时应注意的一些事项:
    除非有当前备份,否则不要执行此操作。
    我会把这两个值都留在主表中。这样,如果你必须从一些旧的文件中找出你需要访问的记录,你就可以做到。 执行此操作时,请将数据库取下来进行维护,并将其置于单用户模式。当您执行类似的操作时,最不需要做的就是当您处于流中时,用户试图进行更改。当然,在单用户模式下的第一个操作就是上面提到的备份。当使用量最轻时,您可能应该安排一段时间的停机时间。 先测试dev!这也应该让你知道你需要多长时间才能结束生产。此外,您还可以尝试几种方法来查看哪种方法最快。
    请务必提前与用户沟通,数据库将在计划的维护时间和他们可以预期的时间停机。确保正时正常。当人们计划晚点运行季度报告,而数据库不可用且他们不知道时,这真的让人生气。
    有相当多的记录,您可能希望批量运行子表的更新(不使用级联更新的一个原因)。这可能比尝试用一次更新更新500万条记录要快。但是,不要一次更新一个记录,否则明年您仍将在这里执行此任务。
    删除所有表中guid字段的索引,然后在完成后重新创建。这将提高变更的性能。

        2
  •  0
  •   David Aldridge    17 年前

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

    禁用约束。

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

    启用pk,然后启用fk。

        3
  •  0
  •   George Eadon    17 年前

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

    说了这句话,我希望1比你的其他想法更好,假设它们都符合你的要求。

    任何涉及到更新子表的触发器的操作似乎都很容易出错,并且过于复杂,可能无法执行1。

    假设新的ID永远不会与旧的ID冲突是否安全?否则,基于一次更新一个ID的解决方案将不得不担心冲突——这会很快变得混乱。

    你考虑过使用吗 CREATE TABLE AS SELECT (CTA)用新ID填充新表?您将复制现有表,这将需要额外的空间,但这可能比更新现有表更快。其思想是:(i)使用CTA创建新表,用新ID代替旧ID;(i i)在新表上创建适当的索引和约束;(i i i)删除旧表;(iv)将新表重命名为旧名称。

        4
  •  0
  •   user38123    17 年前

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

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