如何在不锁定表的情况下向 Postgres 中的 ENUM 添加新值?

Posted

技术标签:

【中文标题】如何在不锁定表的情况下向 Postgres 中的 ENUM 添加新值?【英文标题】:How can I add a new value to an ENUM in Postgres without locking the table? 【发布时间】:2019-11-18 09:52:35 【问题描述】:

我尝试了两种方法。

方法 1:使用添加的新值创建一个新的 ENUM 并就地切换数据类型:

-- Rename existing enum
ALTER TYPE animal_species RENAME TO animal_species_old;

-- Create new enum with new value
CREATE TYPE animal_species AS ENUM (
  'dog',
  'cat',
  'elephant'
);

-- Update the column of Animals to use the new enum
ALTER TABLE "Animals" ALTER COLUMN species SET DATA TYPE animal_species USING species::text::animal_species;

DROP TYPE animal_species_old;

方法 2:使用临时列

-- Create new enum type with a new name (this will be the name of the enum from now on)
CREATE TYPE animal_type_enum AS ENUM (
  'dog',
  'cat',
  'elephant'
);

-- Create a temporary column
ALTER TABLE "Animals" ADD COLUMN species_new animal_species_enum;

-- Copy existing species into new column
UPDATE "Animals" SET species_new = species::text::animal_species_enum;

-- Drop old species column
ALTER TABLE "Animals" DROP COLUMN species;

-- Rename new column
ALTER TABLE "Animals" RENAME COLUMN species_new TO species;

-- Drop old enum
DROP TYPE animal_species;

在这两种情况下,都会创建锁并关闭我的应用程序。我相信第二种方式比第一种表现更好,但停机时间仍然无法接受。该表有数百万行。

请注意,我非常愿意使用除 ENUM 之外的其他东西——我正在考虑在“动物”中使用外键“species_id”创建一个“物种”表,但据我所知,这将创建相同的锁定问题(考虑到引入新的外键约束,可能会更糟)。

感谢您的帮助!

【问题讨论】:

【参考方案1】:

方法3,只需给枚举添加一个新值:

ALTER TYPE animal_type_enum ADD VALUE 'snake';

如果您经常添加或删除新的查找值,单独的查找表是一个非常更好的选择。

添加新值是一个简单的INSERT 操作,不会锁定任何内容(尤其是不是引用查找表的表)。

虽然外键检查确实增加了一些开销,但它们并不重要(假设 FK 列已正确索引),除非您非常频繁地进行批量插入或删除。

对于单行 INSERT 或 DELETE(或仅“数百”行),您可能甚至不会注意到 FK 查找的开销 - 特别是在查找表很小且仅包含几行的情况下。

【讨论】:

太好了,谢谢——看起来这是在 PG 9.1 中添加的。我根本没想到他们会添加这样的功能!仍然无法从 ENUM 中删除一个条目(我可以看到这将如何导致问题)所以我的回滚迁移仍然是临时枚举的废话,但我认为这很好。

以上是关于如何在不锁定表的情况下向 Postgres 中的 ENUM 添加新值?的主要内容,如果未能解决你的问题,请参考以下文章

如何让机器人在不使用命令的情况下向特定频道中的特定公会发送消息

如何在不缩小r闪亮中的矩阵大小的情况下向输入矩阵添加列?

如何在不使用 kml 的情况下向 android studio 中的谷歌地图应用程序添加大量多边形

如何在不知道标识符的情况下向聚合发送命令?

如何在不阻止 textView 触摸的情况下向所有 UITextView 添加一个 UIGestureRecognizer

在不锁定表的情况下运行 MySQLDump