Postgres 9.6中ALTER COLUMN TYPE varchar(N)是否重写表?新版本如何处理?
大表字段长度扩容(无锁/不重写表)的PostgreSQL新方案
作为一个早年在PostgreSQL 8.4时代踩过巨坑的老鸟,来聊聊这个大表字段长度扩容的头疼问题!
早年PostgreSQL 8.4的无奈操作
当年我碰到过一模一样的场景:要把某个表的字段从varchar(50)改成varchar(100),但那张表有几千万行数据,还被业务高频调用,常规的ALTER TABLE根本不敢用——一执行就会重写整个表,锁表时间长到业务直接雪崩。那时候没别的办法,只能冒着风险手动去修改系统表pg_attribute里的对应字段记录,现在想想都后怕,毕竟直接改系统表搞不好就把数据库玩崩了。
新版本PostgreSQL的优雅解决方式
后来在几个技术讨论里挖到了关键线索,才发现从PostgreSQL 9.2及以后的版本,针对变长字符类型(varchar、text)的长度扩容,官方已经做了优化,完全不需要重写表了!
具体操作步骤
- 先确认你的字段是
varchar(n)类型,且是扩容(缩小长度的话还是会重写表,这个要注意) - 直接执行这条SQL就行:
ALTER TABLE your_table ALTER COLUMN your_column TYPE varchar(100); - 划重点:这个操作在新版本里是轻量级元数据修改,只会更新系统表的字段约束信息,不会扫描或重写任何数据行,锁表时间极短——基本就是修改元数据的那几秒,完全不会影响大表的正常使用。
原理揭秘
其实PostgreSQL里的varchar(n)本质上就是个长度约束,实际存储和text类型没区别,只是在插入或更新数据时会检查长度是否符合限制。所以扩容这个约束,只需要修改pg_attribute系统表中的atttypmod字段(这个字段记录了varchar的长度限制值),根本不需要碰实际的数据行,自然也就不用重写表了。
必看注意事项
- 仅适用于扩大长度限制:如果是要缩小长度(比如从
varchar(100)改到varchar(50)),数据库必须扫描全表检查所有数据是否符合新的长度限制,这时候还是会重写表,大表操作一定要谨慎。 - 虽然操作轻量,但建议先在测试环境验证,并且选在业务低峰期执行——毕竟元数据修改也需要短暂的锁,稳妥点总没错。
- 绝对不要再像早年那样手动改
pg_attribute了!新版本的ALTER TABLE已经把这个操作封装得安全又高效,完全没必要冒风险。
内容的提问来源于stack exchange,提问作者orokusaki
相关产品推荐
相关产品推荐

