我对一个非常大的表(近3000万行)上的ALTER TABLE
命令有疑问。其列之一是varchar(255)
,我想将其调整为varchar(40)
。基本上,我想通过运行以下命令来更改列:
ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40);
如果过程很长,我没问题,但是在ALTER TABLE命令期间,我的表似乎不再可读。有没有更聪明的方法?也许添加一个新列,从旧列中复制值,删除旧列,最后重命名新列?
任何线索将不胜感激!预先感谢,
注意:我使用PostgreSQL 9.0。
Resize a column in a PostgreSQL table without changing data上有关于如何执行此操作的说明。您必须修改数据库目录数据。正式执行此操作的唯一方法是使用ALTER TABLE,并且您已经注意到,更改将在运行时锁定并重写整个表。
请确保在更改此内容之前先阅读文档的Character Types部分。这里要注意各种奇怪的情况。将值存储到行中时,将进行长度检查。如果您在其中限制了一个较低的限制,那根本不会减少现有值的大小。进行更改后,最好对整个表进行扫描以查找字段长度大于40个字符的行。您需要弄清楚如何手动截断这些锁-这样您就可以锁住一些超大的锁-因为如果有人尝试更新该行上的任何内容,那么此时它将拒绝它太大它会存储该行的新版本。随之而来的是用户狂欢。
VARCHAR是一个可怕的类型,仅在PostgreSQL中存在,只是为了遵守其与SQL标准相关的可怕部分。如果您不关心多数据库兼容性,请考虑将数据存储为TEXT并添加约束以限制其长度。您可以更改约束而不会出现此表锁定/重写问题,并且约束可以执行更多的完整性检查,而不仅仅是弱长度检查。
在PostgreSQL 9.1中,有一个更简单的方法
http://www.postgresql.org/message-id/[email protected]
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,与某些其他数据库不同,它非常聪明,仅使用足够的空间来容纳字符串(甚至对更长的字符串使用压缩),因此即使您的列声明为VARCHAR(255)-如果您存储40个字符列中的字符串,空间使用量将为40字节+ 1字节的开销。
短字符串(最多126个字节)的存储要求是1个字节加上实际的字符串,其中包括空格性格。较长的字符串的开销为4个字节,而不是1个字节。长字符串由系统自动压缩,因此磁盘上的物理需求可能更少。也很长的值存储在后台表中,以免干扰快速访问较短的列值。
(http://www.postgresql.org/docs/9.0/interactive/datatype-character.html)
VARCHAR中的大小规范仅用于检查所插入值的大小,它不会影响磁盘布局。实际上,VARCHAR and TEXT fields are stored in the same way in Postgres。
我在尝试将VARCHAR从32截断为8并获得ERROR: value too long for type character varying(8)
时遇到了同样的问题。我想尽可能地接近SQL,因为我使用的是类似JPA的自制结构,我们可能必须根据客户的选择切换到不同的DBMS(PostgreSQL是默认的)。因此,我不想使用更改系统表的技巧。
我在USING
中使用了ALTER TABLE
语句结束了:
ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8)
USING substr("MyColumn", 1, 8)
正如@raylu所指出的,ALTER
在表上获得排他锁,因此所有其他操作将延迟到完成为止。
如果将更改放入事务中,则不应锁定表:
BEGIN;
ALTER TABLE "public"."mytable" ALTER COLUMN "mycolumn" TYPE varchar(40);
COMMIT;
这对我来说非常有用,在具有超过40万行的表上快速燃烧了几秒钟。
这里是格雷格·史密斯(Greg Smith)描述的页面的the cache。如果也死了,则alter语句如下所示:
UPDATE pg_attribute SET atttypmod = 35+4
WHERE attrelid = 'TABLE1'::regclass
AND attname = 'COL1';
[如果您的表是TABLE1,该列是COL1,并且您想要将其设置为35个字符(根据链接的遗留目的,则需要+4,可能是A.H.在注释中引用的开销)。
在redshift postgresql上,添加新列并用旧列替换新列对我有用,请参阅此链接以获取更多详细信息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;
我发现了一种非常简单的更改大小的方法,即@Size(min = 1,max = 50)批注,它是“ import javax.validation.constraints”的一部分,即“导入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),
.....
)