症状
错误对天花板的描述非常精确:nextval: reached maximum value of sequence “orders_id_seq” (2147483647)——2147483647 正是 int4 的最大值,真正的天花板是列类型而不是序列设置。写入全面失败而读取完全健康,所以它呈现为“表好好的却突然写不进”的假性宕机。高频churn模式(批量导入回滚、删除、重试)会烧掉序列值却不留行,耗尽可能远早于实际存在二十亿行。
诊断思路
先查序列的 last_value 与 max_value 加列类型,int4 列配到顶的序列即确认耗尽;bigint 列配小 MAXVALUE 序列是更罕见的便宜变体(只改序列即可);再枚举所有引用该表的外键列——每个 int4 引用列都是同一天花板的一部分;最后按表大小规划零停机路径。
根因
int4 的 identity/serial 列上限为 2147483647。为其服务的序列耗尽时,每次插入的 nextval 都失败,而表本身完全可读。序列只能扩展到列能存储的极限——列类型才是真正的上限。
修复与验证
小表用带锁窗口的单语句迁移:ALTER COLUMN id TYPE bigint 加 ALTER SEQUENCE … AS bigint;大表走扩展-收缩:加 bigint 列、分批回填、建索引、触发器或 ORM 双写、再切换列。外键依赖同一窗口迁移。监控把序列余量当领先指标——last_value 占列最大值的比例在 70% 告警,下一次耗尽就是计划内迁移而不是事故。绝不要重置序列去复用 ID:间隙重用会招来主键冲突,还会破坏外部系统里的引用。
代码示例
ERROR: nextval: reached maximum value of sequence
"orders_id_seq" (2147483647)
SELECT last_value, max_value FROM orders_id_seq; -- at the cap
id | integer | not null default nextval(...)
BEGIN;
ALTER TABLE orders ALTER COLUMN id TYPE bigint;
ALTER SEQUENCE orders_id_seq AS bigint MAXVALUE 9223372036854775807;
COMMIT;
-- expand
ALTER TABLE orders ADD COLUMN id_big bigint;
-- backfill in batches
UPDATE orders SET id_big = id WHERE id BETWEEN 1 AND 10000000;
-- index, dual-write via trigger or ORM, then contract
ALTER TABLE orders DROP COLUMN id;
ALTER TABLE orders RENAME COLUMN id_big TO id;