由 John Doe 八月 21, 2026
你知道 PostgreSQL 18 中,关于“数据库约束(Constraints)”的最新功能更新,有哪些吗?
目录

核心特性与关键更新
1. 引入时态键(Temporal Keys),原生支持时态数据建模
时态数据库将时间作为数据模型的一等公民。PG18 填补了时间维度管理的空白,引入了对时态主键、时态唯一键和时态外键的原生支持。
应用场景:追踪带有有效期的历史数据(如员工各历史阶段的薪资),或防止资源在同一时间段内被重叠使用(如酒店房间的重复预订)。
核心语法与实现机制:
- 主键 / 唯一键:针对范围(Range)类型数据,在定义语句末尾添加
WITHOUT OVERLAPS(无重叠)子句,结合业务标量键(如房间 ID)一起使用。 - 时态外键:使用
PERIOD DURING语法,确保引用完整性在特定的时间段内始终保持有效(即子表的时间段必须被包含在父表的时间段内)。 - 底层引擎:要求必须基于 GiST 索引 运行,以实现底层非重叠检测。
与旧方案对比:在 PG18 之前,实现该功能需要依赖极其复杂的“排他约束(EXCLUDE USING gist)”;现在有了清晰且原生的 DDL 语法,大幅降低了开发门槛。
2. 引入全新的 NOT ENFORCED(不强制执行)约束状态
为了赋予数据库部署与变更更高的灵活性,PG18 针对 CHECK(检查约束)和 FOREIGN KEY(外键约束)引入了全新的 NOT ENFORCED 概念。
概念解析:
-
约束会被记录在数据库 Schema 中(
pg_constraint系统目录新增了constraint_enforced列进行状态展示)。 -
但数据库永远不会执行校验,也不会对新数据的插入或更新进行拦截。
-
对底层触发器的影响(以外键为例):创建
NOT ENFORCED的外键不会生成校验触发器(Triggers)。
使用场景:极其适合大型系统的发布与迁移(Rollouts)。开发者可以先无感知地建立好架构规则,后续再通过 ALTER 指令安全地切换为 ENFORCED 状态,进而补齐触发器和历史数据校验。
对比 NOT VALID:已有的 NOT VALID 是“跳过初始历史数据的校验,但会对新数据强制执行规则”;而 NOT ENFORCED 则是“完全停用一切校验机制”。
3. NOT NULL 正式晋升为“一等约束”
经过多年的开发,NOT NULL 从原本仅仅是 pg_attribute 中的一个标志(Flag),被正式重构为一个标准的、具有实体的系统级约束(记录在 pg_constraint 中,类型记为 n)。
获得的新能力:
-
可以自定义约束名称。
-
支持标准的
DROP/ALTER操作。 -
支持属性继承调整:可以使用
SET INHERIT或SET NO INHERIT。可以在父表和子表之间灵活地传递或切断该约束。
性能优化与最佳实践:由于成为了标准约束,它现在也支持 NOT VALID 状态。这意味着你在大型表上添加非空约束时,可以直接使用 NOT NULL NOT VALID,从而有效避免造成全表的大范围读写锁等待(过去通常要先建立 CHECK (col IS NOT NULL) NOT VALID 的曲线救国方案,现在可以直接操作)。
4. 分区表(Partition Tables)的约束优化
- 支持
NOT VALID外键:PG18 允许在分区表上创建带有NOT VALID标志的外键约束。这意味着开发者可以独立对每一个子分区逐个进行校验,避免了一次性强锁定整张大父表的操作,极大优化了锁的粒度。 - 支持
DROP ONLY语法:修复了旧版本的逻辑限制,现在允许直接在分区表的父级上执行DROP ONLY操作来安全移除相关约束。
5. 排序规则(Collation)的约束限制收紧
非确定性排序规则(Nondeterministic Collations)容易导致意料之外的对比结果,甚至引发 pg_dump 和 pg_upgrade 崩溃。为解决此隐患,PG18 制定了更严格的强制规定:
所有建立主键(Primary Key)与外键(Foreign Key)关联关系的列,必须满足以下条件之一:
- 双方均使用明确的确定性(Deterministic)排序规则。
- 如果使用非确定性排序规则,则双方必须使用完全一致的同一种排序规则。
总结
PostgreSQL 18 的约束系统更新,不仅在逻辑层面补齐了时态数据库的强大拼图,更在系统运维层面(大表锁机制、分阶段部署、分区表优化)给予了开发者和 DBA 前所未有的灵活性和安全保障。