DBA:在PostgreSQL数据库之间传输SEQUENCE值

如果表中可能有任何删除,并且序列号“ auto-increment”字段的最后分配值如何转移到另一个PostgreSQL数据库中,而“仅替换max(pk)”不再起作用?

很少有人知道,即使PG不提供高达10版的功能,也无法从另一个会话中 找到该字段的序列的最后一个值 ,但这仍然可以实现。



PostgreSQL支持由序列伪类型定义的“自动增量”字段:
数据类型smallserial,serial和bigserial不是实类型,它们只是用于创建具有唯一标识符(类似于某些DBMS中的AUTO_INCREMENT属性)的列的便捷工具。
从技术上讲,这只是字段的默认定义和SEQUENCE对象生成的值的自动链接。 有时我想研究一下这些值-例如, 将它们转移到结构相似的数据库中

但这不容易做到:
并发
返回从当前会话的该序列的上一个nextval调用返回的值 (如果从未在给定会话中为给定序列调用nextval,则会返回错误。)由于此值受会话范围的限制,因此此函数给出可预测的结果,而不管随后是否在其他会话中调用了nextval。

pg_sequences系统视图
从PostgreSQL 10开始, 出现pg_sequences系统视图 ,其中该信息已经很容易看到。

尽管如此,让我们尝试提取这些信息:

CREATE TABLE tst( id serial --   , val integer ); INSERT INTO tst(val) VALUES(1),(2),(4),(8); 

 TABLE tst; 

 id | val -------- 1 | 1 2 | 2 3 | 4 4 | 8 

这是我们要获取的id = 4值。 但是有人删除了部分记录,在表中已不再存在:

 DELETE FROM tst WHERE id > 2; 

 id | val -------- 1 | 1 2 | 2 

首先,我们将找到对应于我们字段的序列的名称:

 SELECT pg_get_serial_sequence('tst', 'id'); 

 pg_get_serial_sequence ---------------------- public.tst_id_seq 

现在,将结果序列名称用作查询中的表

 SELECT * FROM public.tst_id_seq; 

 last_value | log_cnt | is_called -------------------------------- 4 | 29 | t 

实际上, last_value字段还存储了在调用时序列设法生成的“最后”值。

现在,让我们构建一个简单的脚本,使用dblink模块将序列值从一个数据库传输到另一个数据库:

 --   ,    SELECT ( SELECT nlv FROM dblink( 'host=... port=5432 dbname=... user=... password=...' , $q$ SELECT setval(pg_get_serial_sequence('$q$ || quote_ident(sequence_schema) || $q$.$q$ || quote_ident(sequence_table) || $q$', '$q$ || sequence_column || $q$'), $q$ || lv || $q$) $q$ ) T(nlv bigint) --   ) nlv , * FROM ( SELECT ( SELECT relname FROM pg_class WHERE oid = (dp).refobjid ) sequence_table , ( SELECT attname FROM pg_attribute WHERE (attrelid, attnum) = ((dp).refobjid, (dp).refobjsubid) ) sequence_column , * FROM ( SELECT --    - ( SELECT lv FROM dblink( 'dbname=' || current_database() , $q$ SELECT last_value FROM $q$ || quote_ident(sequence_schema) || $q$.$q$ || quote_ident(sequence_name) || $q$ $q$ ) T(lv bigint) --   ,   ""- ) lv , ( SELECT dp FROM pg_depend dp WHERE (classid, objid, refclassid, deptype) = ('pg_class'::regclass, (quote_ident(sequence_schema) || '.' || quote_ident(sequence_name))::regclass, 'pg_class'::regclass, 'a') LIMIT 1 ) dp --      , * FROM information_schema.sequences WHERE sequence_schema IN ('public') --    ) T ) T WHERE sequence_table !~ '^_'; --      

但是请记住,如果源基础上有任何活动,则结果将是不确定的!

Source: https://habr.com/ru/post/zh-CN483424/


All Articles