首页 > 解决方案 > 我们可以更改生产中所有迁移的主键吗?

问题描述

我正在尝试将表主键 id 更改为 uuid。但问题是数据已经在生产中。可以选择重新编写整个迁移,但随后我们丢失了已有的数据。

此外,该表彼此之间的关联太多。那么有没有办法处理这种情况呢?

为此,我们将 phoenix 和 elixir 与 postgres 一起使用。

标签: sqlpostgresqlelixirectophoenix

解决方案


是的。可以通过几个步骤完成任务,其中一些对数据库执行原始 SQL。

  • 迁移 1 在数据库中创建新列,唯一的,不是空的,类型:uuid(正常迁移)用唯一值填充它(例如,使用 UUID 生成器)
  • 迁移 2 用于Ecto.Adapters.SQL.query/4重新分配表中的主键¹
  • 迁移 3 更新引用该表的所有其他表,方法是删除外键,然后更新值 from idto uuid然后创建一个指向uuid²的新外键

¹ 大致如下(未经测试)

defmodule MyRepo.Migrations.ChangeFK do
  def up do
    MyRepo.query("""
    CREATE UNIQUE INDEX CONCURRENTLY foo_pkey_idx ON foo(id);

    ALTER TABLE foos
      DROP CONSTRAINT foo_pkey,
      ADD CONSTRAINT foo_pkey PRIMARY KEY USING INDEX foo_pkey_idx;
    """)
  end

  def down do
    raise "unreversible"
  end
end

² 有点像

defmodule MyRepo.Migrations.AlterFK do
  def up do
    MyRepo.query("""
    ALTER TABLE bars DROP CONSTRAINT foo_pkey;

    UPDATE bars SET foo_id = (SELECT uuid FROM foos WHERE id = foo_id);

    ALTER TABLE bars
      ADD CONSTRAINT foo_pkey
      FOREIGN KEY (foo_id)
      REFERENCES foos (uuid);
    """)
  end

  def down do
    raise "unreversible"
  end
end

推荐阅读