ALTER COLUMN TYPE varchar(N) 是否重写 Postgres 9.6 中的表?

oro*_*aki 3 postgresql ddl varchar postgresql-9.6

在过去

我们用 Postgres 8.4 处理这个问题的方法是手动更新pg_attribute表:

LOCK TABLE pg_attribute IN EXCLUSIVE MODE;
UPDATE pg_attribute SET atttypmod = 104
    WHERE attrelid = 'table_name'::regclass AND
          attname = 'column_name';
Run Code Online (Sandbox Code Playgroud)

column_name是 avarchar(50)并且我们想要 a varchar(100),但是该表太大(数千万行)并且过于频繁地用于重写。

如今

围绕这个主题的内容和答案对于这样一个(至少是轶事)常见问题来说是稀疏和过时的。

但是,在看到至少 3 次讨论可能是这种情况的提示后,我开始认为使用较新版本的 Postgres(我们在 9.6 上),您现在可以运行以下命令:

ALTER TABLE 'table_name' ALTER COLUMN 'column_name' TYPE varchar(100);
Run Code Online (Sandbox Code Playgroud)

...无需重写表格。

这样对吗?

如果是这样,您是否知道 Postgres 文档中存在有关该主题的某些明确信息?

Lau*_*lbe 5

那ALTER TABLE不需要重写。

文档说:

添加带有DEFAULT子句的列或更改现有列的类型将需要重写整个表及其索引。

测试非常简单:
尝试使用一个空表,看看表relfilenode的pg_class行中的列是否发生变化:

SELECT relfilenode FROM pg_class
    WHERE relname = 'table_name';
Run Code Online (Sandbox Code Playgroud)

继续阅读文档,您会看到:

作为一个例外,当更改现有列的类型时,如果USING子句不更改列内容并且旧类型是二进制强制转换为新类型或新类型上的不受约束的域,则不需要重写表;但仍必须重建受影响列上的任何索引。

由于varchar(50)显然是二进制强制转换为varchar(100),因此您的情况不需要重写表,正如上述测试应确认的那样。