克里斯托夫·希斯尔:自定义 `ENUM` 类型列与 `ORDER BY`

克里斯托夫·希斯尔:自定义 `ENUM` 类型列与 `ORDER BY`

💡 原文英文,约900词,阅读约需4分钟。
📝

内容提要

PostgreSQL的自定义ENUM类型是强制数据库约束的好工具,但在使用SELECT查询并想按这些列排序时要小心。如果按ENUM值的定义顺序排序,会出现错误。为了按字母顺序排序,需要将ENUM值转换为TEXT。但这样会导致索引不再适用。解决方法是创建一个不可变的自定义转换函数,并在SELECT查询中使用它。这样就可以按婚姻状况的字母顺序选择人员并使用索引。

🔎

延伸解读

ENUM 排序的默认行为

在 PostgreSQL 中,对自定义 ENUM 列使用 ORDER BY 时,排序依据是 ENUM 值在定义时的顺序,而非字母顺序。例如,定义顺序为 'single', 'married', 'divorced', 'other',则排序结果会按此顺序输出。如果应用程序错误地假设了字母顺序,就会导致 bug。因此,在使用 ENUM 列排序前,必须明确其定义顺序是否符合业务需求。

转换为 TEXT 的代价

若希望按字母顺序排序,一种简单方法是将 ENUM 值转换为 TEXT,例如使用 CAST(marital_status AS TEXT)。但这样会导致基于 ENUM 列的索引失效,查询计划可能退化为顺序扫描,影响性能。文章通过 EXPLAIN 示例展示了这种转换会使索引不再适用,因此在高并发或大数据量场景下需谨慎使用。

自定义不可变函数的解决方案

为了在按字母顺序排序的同时保持索引有效,可以创建一个标记为 IMMUTABLE 的自定义转换函数,将 ENUM 转换为 TEXT。然后基于该函数创建表达式索引。这样,在查询中使用该函数排序时,查询计划会使用索引扫描。但需注意,必须在查询中也使用该函数,否则索引不会生效。

❓

Q&A

PostgreSQL中的自定义ENUM类型有什么作用?

自定义ENUM类型可以强制数据库约束,确保插入的数据符合预定义的值。

在使用SELECT查询时,如何按字母顺序排序ENUM类型的列?

需要将ENUM值转换为TEXT,然后在ORDER BY子句中使用转换后的值进行排序。

为什么简单的类型转换会导致索引失效?

因为简单的类型转换是可变的,可能会导致查询计划使用顺序扫描,而无法利用索引。

如何解决ENUM类型排序时索引失效的问题?

可以创建一个不可变的自定义转换函数,并在SELECT查询中使用该函数。

创建自定义转换函数的步骤是什么?

首先定义一个返回TEXT的函数,然后在创建索引时使用该函数。

使用自定义转换函数后,如何确保查询仍然使用索引?

在SELECT查询中必须使用自定义转换函数,否则查询将回退到顺序扫描。

➡️

继续阅读