【问题标题】:Postgresql enum what are the advantages and disadvantages?postgresql枚举有什么优缺点?
【发布时间】:2011-01-20 01:27:15
【问题描述】:

在我工作的地方,我们使用 postgres 数据库(8.3 即将迁移到 8.4)。目前关于在数据库中使用枚举有一个小的争论。我个人不喜欢 db 枚举类型。除其他外,它将应用程序逻辑放入数据库中,并为代码和数据之间的不匹配创造了可能性。

我想知道 postgres 枚举到底有什么优点(除了可读性)和缺点是什么?

【问题讨论】:

  • 为什么在 DBMS 中有业务(/应用)逻辑不好?好处很简单:如果您需要直接通过 JDBC 连接处理数据或使用另一个前端,而您的业务逻辑在 DBMS 中 - 您无需进行任何更改,您不必弄湿(打破干燥)。

标签: database postgresql


【解决方案1】:

在 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 --- 去吧;只需确保避免过早优化并在生产中衡量您的结果。

在做出决定时,请考虑 Metabase 等流行的 BI 工具不支持对 ENUM 进行过滤,但是,它们可以在 TEXT 列上正常工作。

【讨论】:

  • 但是 ENUM 字段不是像 BI 工具中的文本字段那样处理吗?索引大小与实际表大小有什么关系?
  • @MihailGershkovich:索引和表都占用实际磁盘空间,但分别报告。您可能会看到表总大小的表示,其中可能包括索引的大小,具体取决于基础查询。每个 BI 工具都是不同的,有些工具会以不同的方式处理 ENUM,并在搜索和过滤时提供“下拉”而不是文本字段,而其他工具可能根本不像 Metabase 那样处理它。
  • 我们有一些表通过使用 ENUMS 将它们的实际大小从大约 64 GB 减少到
  • @MihailGershkovich:很有趣。这是哪个版本的 PostgreSQL?您是否已删除/重新创建索引以利用新的 BTREE 重复数据删除?
【解决方案2】:

优势

  1. 减少存储:当定义了 255 个或更少的 ENUM 元素或 256~65535 个元素时,Postgres 每个元组仅使用 1 个字节。这是因为,Postgres 将索引存储在该值的有序集中,而不是存储值的常量文字。对于非常大的表,这可能会显着节省存储空间。

  2. 任意排序

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 可能会很痛苦。

【讨论】:

  • 如果您了解最终用户的 Web 应用程序或 GUI 用户 - 创建一个可以管理 ENUM 的简单小程序的麻烦在哪里?如果您在谈论 DBMS 角色,那么授予他们访问权限的问题在哪里?唯一的借口是缺乏知识……但如果这是问题所在,可能根本不应该使用数据。
  • Postgres 14 的文档说枚举类型占用 4 个字节的磁盘空间:postgresql.org/docs/14/datatype-enum.html
【解决方案3】:

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

【讨论】:

  • 此回复与此处的真实问题无关。使用 PostgreSQL 就更少了。 PostgreSQL 在运行简单事务的同时运行 DDL 非常出色。实际上还有许多其他数据库。你只需要知道怎么做。
【解决方案4】:

作为优势,您还可以进行数据库检查,没有其他枚举值无法记录在列中。对我来说最大的缺点是,只能通过在末尾添加值来修改枚举,但从 Postgres 9.1 开始,它已经成为过去:https://stackoverflow.com/a/7834949/548473

【讨论】:

    【解决方案5】:

    枚举的优点是:

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

    缺点是:

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

    【讨论】:

    • 如果您定义的值控制将修改您的应用程序的行为,那么“添加值需要 DDL 更改”肯定是一个优势吗?否则,您会增加看似无害的数据库操作破坏您的应用程序的风险。
    • 我希望我能够实现一个多语言 ENUM.... 但我不是 C[++/#,无论如何] 程序员,几乎不了解 PostgreSQL 的源代码。但是,如果有这样的事情 - 我会非常喜欢它!还有一个好处:您可以将 ENUM 用于查找表和相应 FK 中的 PK 键。如果您必须更改查找键的值,只需更改 ENUM,DBMS 不需要将更新级联到所有 FK 字段。
    • 可能值得注意的是,性能优于另一个表上的 JOIN 以获得显示值。与文本字段相比,它并不好。 (见我的回答)
    • @Jeff,与文本字段相比,性能相同,如果您的页面数量相同并且您可以利用索引。如果您需要执行全表搜索,或者如果您获取大量条目,则可能会产生巨大影响。对最终事务(在 DBMS 和客户端之间)的影响可能较低,但对 DBMS 内部的进程影响相当大。
    【解决方案6】:

    枚举结合了整数的优点和字符串的优点:它们像整数一样小而快,像字符串一样可读,并且具有安全的额外优点(你不能拼错枚举)。

    但是,如果您不关心可读性,则 int 与 enum 一样好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      • 2012-10-26
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多