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

ams*_*ams 19 sql postgresql ddl database-design

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

给出一个像这样的表

CREATE TABLE foo (
    pkey SERIAL PRIMARY KEY,
    value INTEGER
);
Run Code Online (Sandbox Code Playgroud)

Postgres输出

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

PgAdmin III显示以下作为表的DDL

ALTER table foo RENAME TO bar;
Run Code Online (Sandbox Code Playgroud)

现在重命名表

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;
Run Code Online (Sandbox Code Playgroud)

Postgres输出

ALTER SEQUENCE foo_pkey_seq RENAME TO bar_pkey_seq;
Run Code Online (Sandbox Code Playgroud)

表格的PgAdmin III SQL窗格

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

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

现在重命名序列

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

CREATE TABLE foo (
    pkey SERIAL PRIMARY KEY,
    value INTEGER
);
Run Code Online (Sandbox Code Playgroud)

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

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

nextval()走了.

质询

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

Erw*_*ter 34

serial不是实际的数据类型.手册明确指出:

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

执行以下所有操作后,解析伪数据类型:

  • 创建一个名为的序列 smallserial

  • 创建具有类型的列serial(或bigserial/ tablename_colname_seq分别为integer/ int2)

  • 制作专栏 int8

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

该系统不会知道你是否做了这一切通过手工或伪数据类型的方式smallserial.pgAdmin检查列出的功能,如果满足所有功能,则使用匹配的串行类型简化反向工程DDL脚本.如果不满足其中一个功能,则不会进行此简化.这是pgAdmin所做的事情.对于底层目录表,它们都是一样的.没有这样的bigserial类型.

我很肯定没有办法自动重命名所拥有的序列.你可以跑

ALTER SEQUENCE ... RENAME TO ...
Run Code Online (Sandbox Code Playgroud)

像你一样.系统本身并不关心名称.该列NOT NULL DEFAULT nextval('tablename_colname_seq')存储一个serial(serial),您可以更改序列的名称而不会破坏它 - OID保持不变.数据库中的外键和类似引用也是如此.

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

ALTER TABLE ... RENAME CONSTRAINT ..
Run Code Online (Sandbox Code Playgroud)

也要纠正这一点.

还可以有参考表名称命名的索引.类似程序:

ALTER INDEX .. RENAME TO  ..
Run Code Online (Sandbox Code Playgroud)

您可以对表名进行各种非正式引用.系统无法强制重命名可以命名的对象.它并不关心.

当然,您不希望使引用这些名称的SQL代码无效.显然,您不希望在应用程序逻辑引用它们时更改名称.通常,这对于索引,序列或约束的名称来说不是问题,因为这些通常不是由名称引用的.

在重命名对象之前,Postgres还会获取对象的锁定.因此,如果有并发事务打开,对相关对象有任何类型的锁定,则serial操作将停止,直到这些事务提交或回滚.

系统目录和OID

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

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

SELECT 'foo_pkey_seq'::regclass
Run Code Online (Sandbox Code Playgroud)

如果模式名称在,OID并且表名称是唯一的,则表示与以下内容相同:

SELECT oid FROM pg_class WHERE relname = 'foo_pkey_seq';
Run Code Online (Sandbox Code Playgroud)

大多数目录表的主键在'foo_pkey_seq'::regclass内部,大多数引用都使用OID.