扩大varchar字段长度仅修改pg_attribute.atttypmod元数据,不重写数据,毫秒级完成;缩容、跨类型转换或加using则需重写全表。

扩大 VARCHAR 字段长度本身不重写数据,毫秒级完成;所谓“大表卡顿”,99% 是卡在等锁,不是卡在改字段。
为什么 ALTER COLUMN TYPE VARCHAR(N) 在大表上也很快
PostgreSQL 扩大 VARCHAR 长度,只修改系统表 pg_attribute.atttypmod 的元数据,底层存储和 TEXT 完全一致,不触碰任何一行实际数据。哪怕表有上亿行、几百 GB,只要没锁冲突,执行时间就是 1–3 毫秒。
-
VARCHAR(50)→VARCHAR(200):改一个整数(atttypmod从 54 变成 204),不重写表 ✅ -
VARCHAR(200)→VARCHAR(50):必须重写全表并校验每行长度,极慢 ❌ -
VARCHAR→TEXT:同理不重写,毫秒完成 ✅ - 加
USING子句或跨类型(如INT→VARCHAR):强制重写表 ❌
生产环境必须加 lock_timeout
真正危险的不是 DDL 本身,而是它申请 AccessExclusiveLock 时被长事务阻塞——这时所有新来的读写请求都会排队堆积,雪崩式超时。
- 执行前务必设保护:
SET lock_timeout = '3s'; - 再跑:
ALTER TABLE big_table ALTER COLUMN name TYPE VARCHAR(500); - 若报
ERROR: canceling statement due to lock timeout,说明有未提交事务占着表,查pg_stat_activity干掉它,别硬等 - 函数索引、CHECK 约束、外键引用都可能延长锁持有时间,需提前评估
视图依赖时别硬改 pg_attribute
当 ALTER 报错 cannot alter type of a column used by a view or rule,直接 UPDATE pg_attribute 是高危操作:跳过所有校验,误算 atttypmod 会导致后续查询截断、崩溃甚至数据损坏。
- 首选方案:临时
DROP VIEW→ALTER TABLE→CREATE VIEW(用事务包住) - 次选方案(无视图重建权限时):先转
TEXT(毫秒),再加CHECK约束:ALTER TABLE t ADD CONSTRAINT chk_len CHECK (char_length(col) ,最后低峰期 <code>VALIDATE CONSTRAINT - 绝对避免:
UPDATE pg_attribute后不验证、不备份、不测插入——它改的是数据库的“字典”,不是你的应用层逻辑
最易被忽略的一点:VARCHAR 扩容看似简单,但一旦混入视图、长事务、函数索引或低版本 PostgreSQL(SELECT max(length(col)) 和 SELECT * FROM pg_depend 看清环境再说。











