20

我知道使用SERIAL主键的 PostgreSQL 表最终会由 PostgreSQL 创建一个隐式索引、序列和约束。问题是在重命名表时如何重命名这些隐式对象。下面是我试图通过最后的具体问题来解决这个问题。

给定一个表格,例如:

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

Postgres 输出:

注意:CREATE TABLE 将为串行列“foo.pkey”创建隐式序列“foo_pkey_seq”
注意:CREATE TABLE / PRIMARY KEY 将为表“foo”创建隐式索引“foo_pkey”
查询成功返回,52 毫秒内没有结果。

pgAdmin III SQL 窗格显示了表的以下 DDL 脚本(整理后):

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

现在重命名表:

ALTER table foo RENAME TO bar;

查询成功返回,17 毫秒内没有结果。

pgAdmin 三:

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

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

现在重命名序列:

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

ALTER SEQUENCE foo_pkey_seq RENAME TO bar_pkey_seq;

查询成功返回,17 毫秒内没有结果。

pgAdmin 三:

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

没了DEFAULT nextval('foo_pkey_seq'::regclass),

问题

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

1 回答 1

34

serial不是实际的数据类型。手册指出

数据类型smallserial和不是真正的类型,而仅仅是创建唯一标识符列的符号serial方便bigserial

伪数据类型被解析为所有这些:

  • 创建一个名为的序列tablename_colname_seq

  • 创建具有类型的列integer(或int2/int8分别用于smallserial/ bigserial

  • 做专栏NOT NULL DEFAULT nextval('tablename_colname_seq')

  • 使列拥有序列,以便自动删除它

系统不知道您是手动还是通过伪数据类型完成了所有这些操作serial。pgAdmin 检查列出的功能,如果所有功能都满足,则反向工程 DDL 脚本将使用匹配serial类型进行简化。如果不满足其中一个特征,则不会发生这种简化。这就是 pgAdmin 所做的事情。对于基础目录表,它都是一样的。没有serial这样的类型。

无法自动重命名拥有的序列。你可以运行:

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 在重命名对象之前也会获取对象的锁定。因此,如果有打开的并发事务对相关对象具有任何类型的锁定,则您的RENAME操作将停止,直到这些事务提交或回滚。

系统目录和 OID

数据库模式存储在系统模式的系统目录表中pg_catalog手册中的所有详细信息都在这里。如果您不确切知道自己在做什么,则根本不应该弄乱这些表。一个错误的举动,你可以打破你的数据库。使用 Postgres 提供的 DDL 命令。

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

SELECT 'foo_pkey_seq'::regclass

如果架构名称在 中search_path并且表名称是唯一的,那么您将获得相同的结果:

SELECT oid FROM pg_class WHERE relname = 'foo_pkey_seq';

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

于 2013-02-01T17:29:03.013 回答