Postgresql枚举有哪些优点和缺点?

js5cn81o  于 2023-03-08  发布在  PostgreSQL
关注(0)|答案(7)|浏览(248)

在我工作的地方,我们使用postgres数据库(8.3很快就会迁移到8.4),目前在数据库中使用枚举的问题上有一个小争论,我个人不喜欢db枚举类型,它将应用程序逻辑放在数据库中,并可能造成代码和数据之间的不匹配。
我想知道postgres枚举的优点到底是什么(除了可读性),缺点是什么?

bjp0bcyl

bjp0bcyl1#

枚举的优点是:

  • 性能更好。您可以只显示从核心表中获得的内容,而不必使用单独的查找表将代码转换为值,也不必使用应用程序逻辑将代码转换为值。这在数据仓库应用程序中特别有用。
  • 即席SQL更易于编写

缺点是:

  • 将显示值编码到数据库ddl中是一种糟糕的形式。如果您在应用程序代码中将枚举值转换为不同的显示值,那么您就失去了使用枚举的许多优点。
  • 添加值需要更改DDL
  • 使语言本地化变得困难
  • 数据库可移植性降低
uoifb46i

uoifb46i2#

枚举合并整型和字符串的优点于一身:它们像int一样小而快,像字符串一样可读,还有一个额外的优点是安全(你不会拼错枚举)。
然而,如果你不关心可读性,int和enum一样好。

yzuktlbb

yzuktlbb3#

在PostgreSQL 13中,btree索引现在支持去重。如果我们以下面的真示例子为例,使用ENUM来表示一个拥有1亿行的日志表中的HTTP方法:

public | test_http_enum_idx | index | postgres | test | permanent   | 789 MB  | 
public | test_http_test_idx | index | postgres | test | permanent   | 789 MB  |

我们可以看到两者的索引大小是相同的,对于一个非规范化的表,每行节省几个字节并不能真正弥补缺点。

**PG 13+的经验法则:**使用ENUM将列约束为一组固定/静态值;不要使用它们来保存磁盘空间。
**可能的例外:**如果静态值的ENUM可以帮助您避免代价高昂的JOIN或FK ---那就去做吧;只需确保避免过早优化并在生产中衡量结果。

在做决定时,请考虑流行的BI工具,如Metabase,不支持对ENUM进行过滤,但是,它们可以很好地对TEXT列进行过滤。@solaris:报告元数据库0.42.1和更高版本支持对ENUM值进行筛选。

2skhul33

2skhul334#

DB检查的好处是,没有其他枚举值不能记录在列中。对我来说最大的缺点是,只能通过在末尾添加值来修改枚举,但从Postgres 9.1开始,这已经是过去式了:https://stackoverflow.com/a/7834949/548473

3duebb1j

3duebb1j5#

优点

1.减少存储:当定义了255个或更少的ENUM元素时,Postgres每个元组只使用1个字节,或者256~65535个元素使用2个字节。这是因为,Postgres不是存储值的常量文字,而是存储该值的有序集合中的索引。对于非常大的表,这可能证明是一个显著的存储空间保存。
1.任意排序

CREATE TABLE opening_hours(
    week_day ENUM ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'),
    opening_time TIME,
    closing_time TIME
);

如果您按week_day排序,它将按您指定的顺序排序,这在上面的情况下很方便。
1.廉价约束:与在应用程序代码或一些复杂的数据库约束中进行检查不同,枚举检查以一种廉价的方式只添加了某些值。

缺点

  • 选项列表不能由最终用户控制,因为ENUM是架构的一部分
  • 要查看选项列表,需要执行其他查询
  • 字符串操作和函数在ENUM上不起作用这是因为ENUM是一个独立于内置数据类型(如NUMERIC或TEXT)的数据类型。这可以通过在操作时将ENUM值转换为TEXT来克服。然而,使用ORM时可能会很痛苦。
3hvapo4f

3hvapo4f6#

与ENUM字段或不带外键的文本字段相比,我更喜欢带外键的文本字段。
带外键的文本字段的优点:

  • 查找返回文本值而不需要连接。
  • 插入强制引用完整性。
  • 定义外键可能值的表可以很容易地修改。

缺点:

  • 与ENUM字段相比,文本字段需要额外的存储空间。在大多数情况下,这不太可能成为问题。
  • 插入需要额外的查找来实施引用完整性。在大多数情况下,这不太可能成为问题。

示例:

create table example_table_example_type (
  example_type text primary key
);

create table example_table (
  example_type text not null references example_table_example_type(example_type),
  ...other fields...
);
bnl4lu3b

bnl4lu3b7#

关键是,如果允许应用程序执行DDL,它们更有可能导致阻塞或冲突。DDL最好离线执行,即在单用户模式下执行。

相关问题