← 返回题目列表

PostgreSQL ENUM、CHECK 约束和字典表应该怎么选?

中等 第 29 / 31 题 更新于 2026/07/30
PostgreSQLENUMCHECK字典表

简化版

PostgreSQL ENUM 适合稳定、少变化的取值;CHECK 适合简单约束且便于随 DDL 变更;字典表适合运营可配置、需要展示文案、排序、启停和扩展属性的取值。核心取舍是稳定性、变更成本和治理需求。

详细版

状态字段可以用 ENUM、CHECK 或字典表表达。ENUM 类型语义强,存储紧凑,但修改取值需要 DDL,删除或重命名值比较麻烦。

CHECK (status IN (...)) 简单直观,约束在表上,适合少量稳定值。字典表最灵活,但需要 join 或缓存,并且强一致约束需要外键或应用校验。

面试时不要说某一种绝对最好。订单状态这种强业务状态可用 CHECK 或 ENUM,渠道来源、行业分类这类配置更适合字典表。

完整版教学

一、为什么同一个状态有多种建模方式

数据库字段取值有限时,需要在“约束强度”和“变更灵活性”之间取舍。约束越强,脏数据越少;变更越灵活,运营和业务迭代越方便。

PostgreSQL 提供 ENUM、CHECK、外键字典表等方式。它们看似都能限制取值,实际维护体验完全不同。

选型前先问:这个值会不会频繁新增?是否需要展示文案?是否参与核心状态机?

二、ENUM 的特点

ENUM 是数据库类型,字段只能存该类型定义的值。

CREATE TYPE order_status AS ENUM ('CREATED', 'PAID', 'CLOSED');

CREATE TABLE orders (
  id bigint PRIMARY KEY,
  status order_status NOT NULL
);

优点是语义强、类型清楚。缺点是枚举值演进需要 DDL,历史版本兼容和回滚要谨慎。

三、CHECK 约束的特点

CHECK 直接在表字段上声明条件:

CREATE TABLE orders (
  id bigint PRIMARY KEY,
  status text NOT NULL,
  CHECK (status IN ('CREATED', 'PAID', 'CLOSED'))
);

它比 ENUM 更像表级规则,修改约束也需要 DDL,但对应用类型绑定较少。适合取值少、变化不频繁的字段。

四、字典表的特点

字典表把取值变成数据:

dict_type = order_source
code = app
name = App 下单
enabled = true
sort_no = 10

它能支持展示名、排序、多语言、启停、备注等扩展属性。代价是查询或应用层要翻译 code,完整性要靠外键或校验。

方案适合不适合
ENUM极稳定状态频繁变更
CHECK简单有限值需要展示配置
字典表可配置取值强状态机随意扩展

五、状态机字段要特别谨慎

订单状态、支付状态不是普通字典。它们控制业务流程,新增一个状态往往意味着代码、消息、报表、权限都要改。

这类字段不应该让运营直接在字典表加值后立刻生效。即使用字典表展示名称,状态流转规则仍要在代码或状态机配置中严格控制。

数字例子:订单状态从 5 个变成 6 个,涉及创建、支付、取消、退款、售后 5 条链路;不是加一行字典那么简单。

六、常见误区与追问

  • 误区:ENUM 性能好,所以所有状态都用 ENUM。 变更成本和回滚风险也要考虑。
  • 误区:字典表最灵活,所以能替代状态机。 核心状态流转不能只靠字典项控制。
  • 误区:CHECK 约束没必要。 它能阻止非法值进入数据库,是很直接的数据保护。
  • 追问:运营可配置取值用什么? 通常用字典表,支持名称、排序、启停和扩展属性。
  • 追问:稳定技术状态用什么? ENUM 或 CHECK 都可以,取决于团队对 DDL 演进的接受度。

七、加强记忆

记忆钩子:ENUM 像刻在数据库类型里的名单,CHECK 像门口检查规则,字典表像后台可维护的花名册。

回答这题按“稳定性、变更成本、展示治理、状态机边界”来选型。这样能体现你不是为了炫 PostgreSQL 特性,而是在做可维护的数据建模。