使用 AWS DMS 迁移后 PostgreSQL 主键序列丢失

Jon*_*man 5 postgresql amazon-rds

我最近使用 AWS Migration Service 将自托管 Postgres 数据库迁移到 AWS RDS。
Postgres 版本:10.6

我注意到我的所有主键不再设置为“序列”,当我尝试手动添加序列时,它从 1 开始,而不是继续已设置的计数。

我使用 Rails 和数据库,所以我的 sql 技能相当低。我通常可以找到插入和更新的方法,但这不是我有太多经验的领域。

我的问题有两部分:

  1. 如何修复单个表?在继续之前,我想了解并测试我正在做的事情。
  2. 有没有办法可以将此修复应用于我拥有的每个表,而无需手动修改每个表?

Jon*_*man 6

在 @a_horse_with_no_name 为我指明了正确的方向并与 AWS 聊天后,我能够回答我自己的问题,至少如果您使用的是 AWS Database Migration Service (DMS)。

问题是,DMS 只关注数据本身,而不是真正的模式(对我来说,这似乎是一个重大疏忽,特别是如果您使用相同的数据库技术,但这是另一个问题)。因此架构本身不会迁移。该文档并没有真正明确这一点。

要解决此问题:

  1. 停止(如果仍然存在)现有 AWS DMS 迁移
  2. 删除现有的迁移数据库,并创建一个新的空架构以供使用
  3. 按照此处的步骤https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/CHAP_Installing.html安装和设置 Amazon Schema 对话工具 (SCT)
  4. 连接到两个数据库后,请按照此处的步骤https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/CHAP_Converting.html来“转换”您的架构(我为此完成了整个“公共”架构)数据库以确保涵盖所有内容
  5. 创建或修改您的 AWS DMS 迁移,确保目标表准备模式 =“TRUNCATE”并禁用目标数据库上的外键。如果进行修改,请确保在询问时“重新启动”而不是恢复

我还没有测试的是如何处理我正在迁移实时数据库的事实。因此,迁移完成后,目标数据库上的序列可能已过时。我相信我可以稍后进入 SCT 并仅迁移序列,但我还没有对此进行测试。


ccj*_*mne 2

除非您错过了某些内容并且可以再次处理迁移(使用不同的参数?我从未使用过 AWS Migration Service,但我认为它应该保留serial列的完整性...),否则您将需要重新创建序列也。


我大约一年前遇到过类似的情况,并在 SO 上写了这个答案

这是它的要点:

CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq'); 
Run Code Online (Sandbox Code Playgroud)

这将创建一个序列foo_a_seq,其值比 中的值nextval高 1 (或者如果没有记录)。maxfoo.a1foo

我还继续设置了一个Function快速应用于所有需要的表/列的方法:

CREATE OR REPLACE FUNCTION make_into_serial(table_name TEXT, column_name TEXT) RETURNS INTEGER AS $$
DECLARE
    start_with INTEGER;
    sequence_name TEXT;
BEGIN
    sequence_name := table_name || '_' || column_name || '_seq';
    EXECUTE 'SELECT coalesce(max(' || column_name || '), 0) + 1 FROM ' || table_name
            INTO start_with;
    EXECUTE 'CREATE SEQUENCE ' || sequence_name ||
            ' START WITH ' || start_with ||
            ' OWNED BY ' || table_name || '.' || column_name;
    EXECUTE 'ALTER TABLE ' || table_name || ' ALTER COLUMN ' || column_name ||
            ' SET DEFAULT nextVal(''' || sequence_name || ''')';
    RETURN start_with;
END;
$$ LANGUAGE plpgsql VOLATILE;
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

SELECT make_into_serial('foo', 'a');
Run Code Online (Sandbox Code Playgroud)