Postgres 序列不同步
Postgres Sequence out of sync
我是 运行 具有 bucardo 和 postgres 的多主机设置。
我发现我的一些 table 序列彼此不同步。特别是自动递增的 id。
示例:
db1 - table1
INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
新行的id是1
db2 - table1
INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
新行的id是1
db2上新行的id应该是2,因为bucardo已经复制了db1的数据,但是db2的自增是基于:
nextval('oauth_sessions_id_seq'::regclass)
如果我们检查 "oauth_sessions_id_seq",我们会看到最后一个值为 0。
呸……有道理吗?
无论如何,我可以执行以下任一操作吗?
使用 bucardo 复制会话 tables,以便共享每个 DB 的会话?
操作上面的默认自动递增函数以考虑 table?
中的最大现有项目
如果你有什么更好的想法,欢迎提出来,有问题尽管提问,谢谢大家的帮助。
您将不得不更改您的 id 生成方法,因为根据常见问题解答中的评论,没有 Bucardo 解决方案。
Can Bucardo replicate DDL?
No, Bucardo relies on triggers, and Postgres does not yet provide DDL
triggers or triggers on its system tables.
由于 Bucardo 使用触发器,它不能 "see" 改变序列,只能改变它复制的表中的数据。序列是不支持触发器的有趣对象,但您可以手动更新它们。我想你可以在 INSERT
之前添加类似下面的代码,但仍然可能存在问题。
SELECT setval('oauth_sessions_id_seq', (SELECT MAX(did) FROM distributors));
有关详细信息,请参阅 this question。
我不是完全了解所涉及的所有问题,但您可以手动执行最大值计算并在重试循环中执行插入操作。我怀疑如果您实际上在两个数据库上都进行插入并允许 Bucardo 进行复制,它是否会起作用,但是如果您可以保证一次只更新一个数据库,那么您可以尝试类似 UPSERT
重试循环的方法。有关详细信息,请参阅 this post。循环的 "guts" 可能如下所示:
INSERT INTO distributors (did, dname)
VALUES ((SELECT max(did)+1 FROM distributors), 'XYZ Widgets');
无论数据库(PostgreSQL、Oracle 等)如何,都为每个 table 创建了动态序列,这些序列具有与之关联的主键。
每当发生大量数据导入或有人手动修改 table.
的序列时,大多数序列都会不同步
解决方案:我们可以设置后退序列的唯一方法是取 PK 的最大值 table 并将下一个 val 的序列设置为它。
下面的查询将列出在您的数据库模式中创建的所有序列:
SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';
SELECT MAX('primary_key') from table;
SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1);
我是 运行 具有 bucardo 和 postgres 的多主机设置。
我发现我的一些 table 序列彼此不同步。特别是自动递增的 id。
示例:
db1 - table1
INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
新行的id是1
db2 - table1
INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
新行的id是1
db2上新行的id应该是2,因为bucardo已经复制了db1的数据,但是db2的自增是基于:
nextval('oauth_sessions_id_seq'::regclass)
如果我们检查 "oauth_sessions_id_seq",我们会看到最后一个值为 0。
呸……有道理吗?
无论如何,我可以执行以下任一操作吗?
使用 bucardo 复制会话 tables,以便共享每个 DB 的会话?
操作上面的默认自动递增函数以考虑 table?
中的最大现有项目
如果你有什么更好的想法,欢迎提出来,有问题尽管提问,谢谢大家的帮助。
您将不得不更改您的 id 生成方法,因为根据常见问题解答中的评论,没有 Bucardo 解决方案。
Can Bucardo replicate DDL?
No, Bucardo relies on triggers, and Postgres does not yet provide DDL triggers or triggers on its system tables.
由于 Bucardo 使用触发器,它不能 "see" 改变序列,只能改变它复制的表中的数据。序列是不支持触发器的有趣对象,但您可以手动更新它们。我想你可以在 INSERT
之前添加类似下面的代码,但仍然可能存在问题。
SELECT setval('oauth_sessions_id_seq', (SELECT MAX(did) FROM distributors));
有关详细信息,请参阅 this question。
我不是完全了解所涉及的所有问题,但您可以手动执行最大值计算并在重试循环中执行插入操作。我怀疑如果您实际上在两个数据库上都进行插入并允许 Bucardo 进行复制,它是否会起作用,但是如果您可以保证一次只更新一个数据库,那么您可以尝试类似 UPSERT
重试循环的方法。有关详细信息,请参阅 this post。循环的 "guts" 可能如下所示:
INSERT INTO distributors (did, dname)
VALUES ((SELECT max(did)+1 FROM distributors), 'XYZ Widgets');
无论数据库(PostgreSQL、Oracle 等)如何,都为每个 table 创建了动态序列,这些序列具有与之关联的主键。 每当发生大量数据导入或有人手动修改 table.
的序列时,大多数序列都会不同步解决方案:我们可以设置后退序列的唯一方法是取 PK 的最大值 table 并将下一个 val 的序列设置为它。
下面的查询将列出在您的数据库模式中创建的所有序列:
SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';
SELECT MAX('primary_key') from table;
SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1);