PostgreSQL批量修改字段长度必须用DO块+动态SQL逐表执行,因无原生批量ALTER语法;需筛选表名、安全插值、捕获异常、注意schema和锁表影响。

批量修改字段长度必须用循环 + 动态 SQL
PostgreSQL 没有原生的 ALTER TABLE ... ALTER COLUMN ... TYPE 批量语法,所有“批量”操作本质都是用 PL/pgSQL 封装循环遍历表名,逐个执行 DDL。硬写多条 ALTER TABLE 语句不现实,尤其当涉及几十张表时。
关键点在于:不能直接在 SQL 脚本里用 FOR 或变量拼接表名——必须进函数或 DO 块;且每条 ALTER TABLE 是独立事务步骤,失败会中断整个流程。
- 推荐用
DO $$ ... $$匿名块,避免创建永久函数 - 表名需从
pg_class或information_schema.tables筛选,注意过滤系统表(如relname NOT LIKE 'pg_%') - 字段名固定时,可在循环内硬编码;若也要动态传入,需额外查
information_schema.columns - 务必加
RAISE NOTICE输出当前处理表,便于定位卡点
示例:给所有以 t_qcc_ 开头的表统一扩 remark 字段到 VARCHAR(1000)
以下代码可直接在 psql 中运行(需超级用户权限):
DO $$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT relname AS tabname
FROM pg_class c
WHERE c.relkind = 'r'
AND c.relname LIKE 't_qcc_%'
AND c.relname NOT IN ('t_qcc_log', 't_qcc_archive')
LOOP
BEGIN
EXECUTE format('ALTER TABLE %I ALTER COLUMN remark TYPE VARCHAR(1000)', r.tabname);
RAISE NOTICE 'OK: %', r.tabname;
EXCEPTION WHEN undefined_column THEN
RAISE NOTICE 'SKIP: % (no column "remark")', r.tabname;
WHEN others THEN
RAISE NOTICE 'FAIL: % - %', r.tabname, SQLERRM;
END;
END LOOP;
END $$;说明:
-
%I是安全的标识符插值,自动加双引号防关键字冲突 -
EXCEPTION块捕获常见错误:字段不存在、数据超长、视图依赖等,避免单表失败导致全停 - 没加
USING子句——因为只是扩大VARCHAR长度,且确认无超长数据;若不确定,应前置SELECT MAX(LENGTH(remark)) FROM 表名
跨模式批量修改要显式指定 schema
默认只查 public 模式。如果目标表分布在多个 schema(如 sales、log),必须把 pg_class 和 pg_namespace 关联,并用 nspname 过滤:
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
SELECT c.relname AS tabname
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname IN ('sales', 'log')
AND c.relkind = 'r'
AND c.relname LIKE 'order_%';然后在 EXECUTE format(...) 里拼成 %I.%I 形式,例如:format('ALTER TABLE %I.%I ALTER COLUMN ...', r.nspname, r.tabname)。
漏掉 schema 会导致 relation "xxx" does not exist 错误——这是批量脚本最常踩的坑。
大表批量改字段长度会锁表,别指望“后台悄悄跑”
每个 ALTER TABLE ... TYPE 都会获取 ACCESS EXCLUSIVE 锁,期间该表所有读写阻塞。100 张表 × 平均 2 秒/表 = 至少 3 分钟连续锁表窗口,业务敏感场景不可接受。
- 不能用
CONCURRENTLY——ALTER COLUMN TYPE不支持此选项 - 无法跳过数据重写:即使只是扩
VARCHAR长度,PostgreSQL 仍会重写整行(内部存储格式需对齐),百万行表可能耗时数秒到分钟级 - 真正可行的降级方案只有两个:① 分批次在低峰期执行(如每次最多 5 张表);② 改用“新建列 → 分批 UPDATE → 删旧列 → 改名”三步法,但逻辑复杂得多
实际执行前,一定要先在测试库用同样数据量压测单表耗时,再推算总窗口——这点容易被忽略,结果半夜跑脚本卡住核心交易表。

















