TL;DR 版本:担心这个可能不值得你花时间。
长版:
Postgres 中有一个枚举类型:
create type myenum as enum('foo', 'bar');
使用它与 varchar 或整数字段相关的优点和缺点。主要是专业人士恕我直言。
就大小而言,它存储为oid
, 所以int32
类型。这使它比填充了典型值的 varchar 更小(例如'draft'
, 'published'
, 'pending'
, 'completed'
, 无论你的枚举是什么),并且与类型的大小相同int
。如果你的值很少,a smallint
/int16
无疑会更小。您的一些性能变化将来自那里(更小与更大的领域,即几乎可以忽略不计)。
在每种情况下都可以进行验证,无论是通过对 的内置目录查找enum
,还是对 avarchar
或 an的检查约束或外键int
。您的一些性能变化将来自那里,而且可能也不值得您花时间。
枚举类型的另一个好处是它是有序的。在上面的例子中,'foo'::myenum < 'bar'::myenum'
,使得order by enumcol
. 要使用 avarchar
或 an实现相同的目的int
,您需要一个带有sortidx
列或其他内容的单独表......在这种情况下,如果您想按枚举值排序,枚举可以产生巨大的好处。这给我们带来了(恕我直言)唯一的问题,这与枚举类型如何存储在目录中有关......
在内部,每个枚举的值都带有一个oid
,后者按原样存储在表中。所以它在技术上是一个int32。创建枚举类型时,其值会以正确的顺序存储在目录中。在上面的例子中,'foo'
会有一个oid
低于'bar'
。这使得 Postgres 按枚举值排序非常有效,因为它相当于对int32
值进行排序。
但是,当ALTER
您使用枚举时,您最终可能会遇到更改该顺序的情况。例如,假设您以myenum
now的方式更改上述枚举('foo', 'baz', 'bar')
。出于与效率相关的原因,Postgres 不会oid
为现有值分配新值并重写使用它们的表,更不用说使使用它们的缓存查询计划无效。相反,它会在 中填充一个单独的字段,pg_catalog
以使其产生正确的排序顺序。从那时起,按枚举字段排序需要额外的查找,这实际上相当于将表与带有sortidx
字段的单独值表连接起来——就像你对 avarchar
或 an所做的那样,int
如果你想对它们进行排序.
这通常很好并且完全可以接受。有时,它不是。如果没有,则有解决方案:更改具有枚举类型的表,并将它们的值更改为 varchar。还可以像您一样定位和调整使用它的功能和触发器。然后完全删除该类型,然后重新创建它以获取新的 oid 值。最后将表格改回原来的位置,并重新调整函数和触发器。不是微不足道的,但肯定是可行的。