安全且干净地重命名在Postgres中使用串行主键列的表?

我知道使用SERIAL主键的PostgreSQL表结束了由PostgreSQL创build的隐式索引,序列和约束。 问题是如何重新命名这些隐式对象时重命名表。 以下是我最后想到的具体问题。

给定一个表,如

CREATE TABLE foo ( pkey SERIAL PRIMARY KEY, value INTEGER ); 

Postgres输出

 NOTICE: CREATE TABLE will create implicit sequence "foo_pkey_seq" for serial column "foo.pkey" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo" Query returned successfully with no result in 52 ms. 

PgAdmin III显示下表作为该表的DDL

 CREATE TABLE foo ( pkey serial NOT NULL, value integer, CONSTRAINT foo_pkey PRIMARY KEY (pkey ) ) WITH ( OIDS=FALSE ); ALTER TABLE foo OWNER TO postgres; 

现在重命名表

 ALTER table foo RENAME TO bar; 

Postgres输出

 Query returned successfully with no result in 17 ms. 

表格的PgAdmin III SQL窗格

 CREATE TABLE bar ( pkey integer NOT NULL DEFAULT nextval('foo_pkey_seq'::regclass), value integer, CONSTRAINT foo_pkey PRIMARY KEY (pkey ) ) WITH ( OIDS=FALSE ); ALTER TABLE bar OWNER TO postgres; 

注意额外的DEFAULT nextval('foo_pkey_seq'::regclass),这意味着重命名表不会重命名主键的顺序,但是现在我们有了这个明确的nextval()

现在重命名序列

我想保持数据库的命名一致,所以我试了一下

 ALTER SEQUENCE foo_pkey_seq RENAME TO bar_pkey_seq; Query returned successfully with no result in 17 ms. 

在pgAdmin III中查看SQL窗格我看到了

 CREATE TABLE bar ( pkey serial NOT NULL, value integer, CONSTRAINT foo_pkey PRIMARY KEY (pkey ) ) WITH ( OIDS=FALSE ); ALTER TABLE bar OWNER TO postgres; 

DEFAULT nextval('foo_pkey_seq'::regclass),不见了。

质询

  1. 为什么DEFAULT nextval('foo_pkey_seq'::regclass)语句出现并消失?
  2. 有没有办法重新命名表并使主键序列在同一时间重命名?
  3. 在客户端连接到数据库的时候重命名表然后顺序是否安全?是否有任何并发​​问题?
  4. postgres如何知道使用哪个序列? 有内部使用的数据库触发器吗? 除了表格和序列之外,还有别的什么可以重新命名吗?
  5. 那么由主键创build的隐式索引呢? 应该重新命名? 如果是这样,那怎么办?
  6. 那么上面的约束名称呢? 它仍然是foo_pkey 。 如何重新命名一个约束?

serial不是实际的数据types。 手册明确指出 :

数据typessmallserial,serial和bigserial不是真正的types,而仅仅是为了创build唯一的标识符列表

伪数据types解决了这一切:

  • 创build一个名为tablename_colname_seq的序列

  • 创buildtypes为integer的列(或者分别为smallserial / bigserial int2 / int8

  • 设置列NOT NULL DEFAULT nextval('tablename_colname_seq')

  • 使列自己的序列,以便它自动下降。

系统不知道你是通过手工还是通过伪数据typesserial方式完成了这一切。 pgAdmin检查列出的function,如果全部都满足,则反向工程DDL脚本将使用匹配的串行types进行简化。 如果其中一项function没有得到满足,则这种简化不会发生。 这是pgAdmin所做的。 对于基础目录表,它们都是一样的。 没有这样的serialtypes。

我相当积极,没有办法自动重命名拥有的序列。 你可以跑

 ALTER SEQUENCE ... RENAME TO ... 

像你一样。 系统本身不关心名称 。 列DEFAULT存储一个OID'foo_pkey_seq'::regclass ),您可以更改序列的名称而不会破坏 – OID保持不变。 数据库中的外键和类似的引用也是一样的。

主键的隐式索引绑定到PK约束的名称,如果更改表的名称,则不会更改。 在Postgres 9.2或更高版本中,您可以使用

 ALTER TABLE ... RENAME CONSTRAINT .. 

也要纠正这一点。

也可以使用引用表名称的索引。 类似的程序 :

 ALTER INDEX .. RENAME TO .. 

你可以有各种对表名的非正式引用。 系统不能强制重命名可以任意命名的对象。 它并不在乎。

当然,你不想失效引用这些名字的SQL代码。 显然,当应用程序逻辑引用它们时,你不想改变名称。 通常这对于索引,序列或约束的名称来说不会有问题,因为这些名称通常不会被引用。

在重命名对象之前,Postgres也会获取对象的locking。 因此,如果有并发事务处于打开状态,对所涉及的对象有任何types的locking,则RENAME操作将被停止,直到这些事务提交或回退。

系统目录和OID

数据库模式存储在系统模式pg_catalog中的系统目录的表中。 手册中的所有细节在这里。 如果你不确切地知道你在做什么, 你就不应该搞这些表 。 一个错误的举动,你可以打破你的数据库。 使用Postgres提供的DDL命令。

对于一些最重要的表格,Postgres提供了对象标识符types和types转换以快速获取OID的名称,反之亦然。 喜欢:

 SELECT 'foo_pkey_seq'::regclass 

如果模式名称位于search_path ,并且表名是唯一的,则会给出与以下内容相同的内容:

 SELECT oid FROM pg_class WHERE relname = 'foo_pkey_seq'; 

大多数目录表的主键是oid ,在内部,大多数引用使用OID。