安全且干净地重命名在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),
不见了。
质询
- 为什么
DEFAULT nextval('foo_pkey_seq'::regclass)
语句出现并消失? - 有没有办法重新命名表并使主键序列在同一时间重命名?
- 在客户端连接到数据库的时候重命名表然后顺序是否安全?是否有任何并发问题?
- postgres如何知道使用哪个序列? 有内部使用的数据库触发器吗? 除了表格和序列之外,还有别的什么可以重新命名吗?
- 那么由主键创build的隐式索引呢? 应该重新命名? 如果是这样,那怎么办?
- 那么上面的约束名称呢? 它仍然是
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所做的。 对于基础目录表,它们都是一样的。 没有这样的serial
types。
我相当积极,没有办法自动重命名拥有的序列。 你可以跑
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。