我有一个关于一个非常大的表(几乎有3000万行)上的ALTER TABLE命令的问题。
其中一列是varchar(255),我想将其大小调整为varchar(40)。
基本上,我想通过运行以下命令来更改我的列:
ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40);
如果进程很长,我没有问题,但似乎我的表在ALTER table命令期间不再可读。
有没有更聪明的办法?也许添加一个新列,从旧列复制值,删除旧列,最后重命名新列?
注意:我使用PostgreSQL 9.0。
在不改变数据的情况下,在PostgreSQL表中调整列的大小有一个描述。你得破解数据库目录数据。正式做到这一点的唯一方法是使用ALTER TABLE,正如您所注意到的,change将在运行时锁定并重写整个表。
Make sure you read the Character Types section of the docs before changing this. All sorts of weird cases to be aware of here. The length check is done when values are stored into the rows. If you hack a lower limit in there, that will not reduce the size of existing values at all. You would be wise to do a scan over the whole table looking for rows where the length of the field is >40 characters after making the change. You'll need to figure out how to truncate those manually--so you're back some locks just on oversize ones--because if someone tries to update anything on that row it's going to reject it as too big now, at the point it goes to store the new version of the row. Hilarity ensues for the user.
VARCHAR是一个可怕的类型,它存在于PostgreSQL中只是为了遵守与之相关的SQL标准的可怕部分。如果您不关心多数据库兼容性,可以考虑将数据存储为TEXT,并添加一个约束来限制其长度。你可以在没有表锁/重写问题的情况下改变约束,它们可以做更多的完整性检查,而不仅仅是弱长度检查。
我正面临着同样的问题,试图将VARCHAR从32截断为8,并得到ERROR:值对于类型字符变化(8)太长。我希望尽可能地接近SQL,因为我使用的是自制的类似于jpa的结构,我们可能不得不根据客户的选择切换到不同的DBMS (PostgreSQL是默认的)。因此,我不想使用修改System表的技巧。
我结束了在ALTER TABLE中使用using语句:
ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8)
USING substr("MyColumn", 1, 8)
正如@raylu指出的那样,ALTER在表上获得了一个排他锁,因此所有其他操作将被延迟,直到它完成。