Postgresql – 更改varchar列的大小

我有一个关于在一个非常大的表(近3千万行)的ALTER TABLE命令的问题。 其中一列是一个varchar(255) ,我想调整它的大小varchar(40) 。 基本上,我想通过运行以下命令来更改我的列:

 ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40); 

如果这个过程非常长,我没有问题,但是在ALTER TABLE命令期间,我的表看起来不可读。 有更聪明的方法吗? 也许添加一个新列,从旧列复制值,删除旧列,最后重命名新的?

任何线索将不胜感激! 提前致谢,

注意:我使用PostgreSQL 9.0。

有一个如何在PostgreSQL表中调整列大小而不改变数据的描述 。 您必须破解数据库目录数据。 正式的唯一方法是使用ALTER TABLE,正如你已经注意到的那样,在整个表运行的时候,更改会locking和重写整个表。

确保在更改之前阅读文档的字符types部分。 各种奇怪的情况下要注意这里。 当值存储到行时,长度检查完成。 如果你在那里有一个下限,那么根本不会减less现有值的大小。 在整个表格中扫描整个字段的长度大于40个字符的行是明智的。 你需要弄清楚如何手动截断这些数据 – 所以你只是在超大的数据库上locking了一些locking,因为如果有人试图更新该行的任何内容,现在就会拒绝它,它将存储该行的新版本。 随时为用户欢闹。

VARCHAR是在PostgreSQL中存在的一种可怕的types,只是为了遵守与SQL标准相关的可怕部分。 如果您不关心多数据库兼容性,请考虑将数据存储为TEXT并添加约束来限制其长度。 约束条件可以在没有这个表锁/重写问题的情况下进行更改,而且它们可以执行更多的完整性检查,而不仅仅是弱长度检查。

在PostgreSQL 9.1中有一个更简单的方法

http://www.postgresql.org/message-id/162867790801110710g3c686010qcdd852e721e7a559@mail.gmail.com

 CREATE TABLE foog(a varchar(10)); ALTER TABLE foog ALTER COLUMN a TYPE varchar(30); postgres=# \d foog Table "public.foog" Column | Type | Modifiers --------+-----------------------+----------- a | character varying(30) | 

好吧,我可能迟到了派对,但…

没有必要调整您的案例中的列!

与其他数据库不同,Postgres足够聪明,只需使用足够的空间来适应string(即使对较长的string使用压缩),所以即使列被声明为VARCHAR(255) – 如果将40个字符的string存储在该列的空间使用量将是40个字节+ 1个字节的开销。

短string(最多126字节)的存储要求是1个字节加上实际的string,在字符的情况下包括空格填充。 更长的string有4个字节的开销,而不是1.长string被系统自动压缩,因此磁盘上的物理需求可能会更less。 非常长的值也存储在背景表格中,所以它们不会干扰快速访问较短的列值。

http://www.postgresql.org/docs/9.0/interactive/datatype-character.html

VARCHAR中的大小规格仅用于检查所插入值的大小,不影响磁盘布局。 实际上, VARCHAR和TEXT字段在Postgres中以相同的方式存储 。

我正面临同样的问题试图截断一个VARCHAR从32到8,并获取ERROR: value too long for type character varying(8) 。 我希望尽可能地接近SQL,因为我使用自制的类JPA结构,根据客户的select可能需要切换到不同的DBMS(PostgreSQL是默认的)。 因此,我不想使用改变系统表的技巧。

我结束了在ALTER TABLE USING语句:

 ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8) USING substr("MyColumn", 1, 8) 

如果表正被另一个程序访问,或者表被编入索引,我还没有真正考虑这个影响。 我认为Postgres会自动进行这种操作吗?

这是Greg Smith所描述的页面的caching 。 如果同样死亡,则alter语句如下所示:

 UPDATE pg_attribute SET atttypmod = 35+4 WHERE attrelid = 'TABLE1'::regclass AND attname = 'COL1'; 

在你的表是TABLE1的情况下,这个列是COL1,你想把它设置为35个字符(根据链接,遗留的目的需要+4,可能是AH在注释中引用的开销)。

在redshift postgresql中添加新的列并replace旧的工作,请参考此链接https://gist.github.com/mmasashi/7107430

 BEGIN; LOCK users; ALTER TABLE users ADD COLUMN name_new varchar(512) DEFAULT NULL; UPDATE users SET name_new = name; ALTER TABLE users DROP name; ALTER TABLE users RENAME name_new TO name; END; 

如果你把alter变成一个事务,表不应该被locking:

 BEGIN; ALTER TABLE "public"."mytable" ALTER COLUMN "mycolumn" TYPE varchar(40); COMMIT; 

这对我来说很快,在超过40万行的桌子上只有几秒钟的时间。

我已经find了一个非常简单的方法来改变大小,即注解@Size(min = 1,max = 50),它是“import javax.validation.constraints”的一部分,即“import javax.validation.constraints.Size;”

 @Size(min = 1, max = 50) private String country; when executing this is hibernate you get in pgAdmin III CREATE TABLE address ( ..... country character varying(50), ..... )