恢复后串行字段的默认值更改

Lui*_*mim 5 postgresql

今天我在恢复一个PostgreSQL数据库后发现一个奇怪的行为:所有serial字段默认值的模式都被修剪掉了。

例如:

CREATE TABLE testschema.testtable
(
   id serial, 
   name character varying(255), 
   CONSTRAINT pk_testtable PRIMARY KEY (id)
) 
WITH (
  OIDS = FALSE
)
;


SELECT a.attnum, n.nspname, c.relname, d.adsrc AS default_value
FROM pg_attribute AS a
JOIN pg_class AS c ON a.attrelid = c.oid
JOIN pg_namespace AS n ON c.relnamespace = n.oid
LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum
WHERE a.attnum > 0 
  AND n.nspname = 'testschema' 
  AND c.relname = 'testtable' 
Run Code Online (Sandbox Code Playgroud)

id的DEFAULT_VALUE是nextval('testschema.testtable_id_seq'::regclass)

恢复后,default_value 更改为nextval('testtable_id_seq'::regclass)并且 INSERT 开始失败,因为在其架构上找不到序列。

备份
$ pg_dump -F c -Z 9 -b -h localhost -U postgres -f backup dbname

恢复
$ pg_restore -U postgres -h localhost -l backup > backup.list
$ pg_restore -U postgres -h localhost --disable-triggers -O -d dbname -S postgres -Fc -L backup.list backup

这是一些备份/恢复问题吗?我究竟做错了什么?顺便说一句,PostgreSQL 版本是 9.1.3 x64 运行在 Windows(开发机器)上,但也可以在 Linux 上复制。

Cra*_*ein 4

我运行了与您相同的过程,但得到了不同的结果。当尝试覆盖同一数据库时,使用命令恢复数据库不起作用,因为您没有使用 -c --clean 选项。使用相同的 pg_restore 命令恢复到新数据库是有效的。然而插入新记录仍然是可能的。

这是我采取的步骤。

创建数据库

createdb testdatabase

创建架构

psql -d testdatabase -c 'create schema testschema;'

创建表

psql -d 测试数据库

CREATE TABLE testschema.testtable(
  id serial, name character varying(255), 
  CONSTRAINT pk_testtable PRIMARY KEY (id)
) with (OIDS=false);
Run Code Online (Sandbox Code Playgroud)

注意:CREATE TABLE 将为串行列“testtable.id”创建隐式序列“testtable_id_seq” 注意:CREATE TABLE / PRIMARY KEY 将为表“testtable”创建隐式索引“pk_testtable” CREATE TABLE

插入一些记录

testdatabase=# insert into testschema.testtable (name) values('person1'),('person2');
INSERT 0 2
Run Code Online (Sandbox Code Playgroud)

备份数据库

pg_dump -F c -Z 9 -b -h localhost -U postgres -f backup testdatabase
Run Code Online (Sandbox Code Playgroud)

创建备份列表文件

pg_restore -U postgres -h localhost -l 备份 > backup.list

backup.list相关内容

第2639章 1262 16468 数据库 - 测试数据库 postgres 163;1259 16472 表 testschema testtable postgres 162; 第1259章 16470 序列测试架构 testtable_id_seq postgres 2643; 0 0 testschema testtable_id_seq postgres 2644 拥有的序列;0 0 序列集测试模式 testtable_id_seq postgres 2633; 2604 16475 默认测试架构 ID postgres 2636;0 16472 表数据 testschema testtable postgres 2635; 2606 16477 约束 testschema pk_testtable postgres

恢复备份

pg_restore -U postgres -h localhost --disable-triggers -O -d testdatabase -S postgres -Fc -L backup.list backup
Run Code Online (Sandbox Code Playgroud)

pg_restore 发回错误

pg_restore:[archiver (db)] 无法执行查询:错误:模式“testschema”已存在 pg_restore:[archiver (db)] 来自 TOC 条目 163 的错误;1259 16472 表 testtable postgres pg_restore: [archiver (db)] 无法执行查询: 错误: 关系“testtable_id_seq”已存在

恢复到另一个数据库

createdb testdatabase2
pg_restore -U postgres -h localhost --disable-triggers -O -d testdatabase2 -S postgres -Fc -L backup.list backup
Run Code Online (Sandbox Code Playgroud)

没有收到任何错误

插入更多记录

psql -d testdatabase2

testdatabase2=# insert into testschema.testtable (name) values('person2'),('person3');
INSERT 0 2
Run Code Online (Sandbox Code Playgroud)

查看记录

testdatabase2=# select * from testschema.testtable;

 id |  name   
----+---------
  1 | person1
  2 | person2
  3 | person2
  4 | person3
Run Code Online (Sandbox Code Playgroud)

查看testschema.testtable的表结构

pg_dump --schema-only -t testschema.testtable testdatabase2
Run Code Online (Sandbox Code Playgroud)

正如您在问题中提到的,postgresql 确实重写了默认值

ALTER TABLE ONLY testtable ALTER COLUMN id SET DEFAULT nextval('testtable_id_seq'::regclass);

结论

使用完全相同的命令,尝试恢复同一数据库时确实会发生错误,但恢复到新数据库时,可以添加新记录。

您必须添加 -c 或 --clean 来删除现有对象,以便可以通过 pg_restore 恢复它们。

pg_restore -c -U postgres -h localhost --disable-triggers -O -d testdatabase -S postgres -Fc -L backup.list backup
Run Code Online (Sandbox Code Playgroud)

正如您在问题中提到的那样,Postgresql 确实重写了串行列的默认值,但插入仍然是可能的。

更新答案

使用您提供的查询时,确实在恢复数据库后我在搜索路径中没有看到测试模式。

testdatabase=# SELECT a.attnum, n.nspname, c.relname, d.adsrc AS default_value FROM pg_attribute AS a JOIN pg_class AS c ON a.attrelid = c.oid JOIN pg_namespace AS n ON c.relnamespace = n.oid LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum WHERE a.attnum > 0   AND n.nspname = 'testschema'  AND c.relname = 'testtable';
 attnum |  nspname   |  relname  |             default_value             
--------+------------+-----------+---------------------------------------
      1 | testschema | testtable | nextval('testtable_id_seq'::regclass)
      2 | testschema | testtable | 
Run Code Online (Sandbox Code Playgroud)

但是,当我使用 \d testschema.testtable 时,我确实在 NEXTVAL 的定义中看到了 testschema

testdatabase=# \d testschema.testtable;
                                    Table "testschema.testtable"
 Column |          Type          |                             Modifiers                             
--------+------------------------+-------------------------------------------------------------------
 id     | integer                | not null default nextval('testschema.testtable_id_seq'::regclass)
 name   | character varying(255) |
Run Code Online (Sandbox Code Playgroud)

我在 Postgresql 论坛上找到了这个,其中讨论了我们都看到的差异。

http://archives.postgresql.org/pgsql-admin/2009-06/msg00070.php