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

时间:2019-07-08 20:52:58

标签: sql postgresql enums denormalization

我尝试了两种方法。

方法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”创建一个“ Species”表,但据我所知会产生相同的锁定问题(在引入新的外键约束的情况下,甚至可能更糟)。

感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

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

ALTER TYPE animal_type_enum ADD VALUE 'snake';

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

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

尽管外键检查确实会增加一些开销,但是它们无关紧要(假设FK列已正确索引),除非您非常频繁地批量执行INSERT或DELETE。

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