在 Postgresql 9.3 中将字符串列转换为数组列

Convert String Column to Array Column in Postrgresql 9.3

我在数据库中有一个字符串列需要转换为数组类型。在我还需要设置索引的过程中不要锁定数据库。

ALTER TABLE sites ALTER COLUMN rtb_id TYPE varchar[] USING string_to_array(rtb_id, '');
CREATE INDEX CONCURRENTLY rtb_id_search ON sites(rtb_id) USING array_to_string;
DROP INDEX CONCURRENTLY ix_sites_bundle_trgm_gin ON sites;
DROP INDEX CONCURRENTLY ix_sites_name_trgm_gin ON sites;

是这样吗?

编辑:

ALTER TABLE sites ADD COLUMN rtb_ids varchar[]
...
BEFORE INSERT OR UPDATE ... FOR EACH ROW trigger that sets NEW.rtb_id_new := string_to_array(NEW.rtb_id,' ') for each row.
In batches, UPDATE sites SET rtb_id_new = string_to_array(rtb_id,' ')
...
VACUUM sites; 
CREATE INDEX CONCURRENTLY rtb_ids_search ON sites(rtb_ids) USING array_to_string(rtb_ids, '');

ALTER TABLE sites DROP COLUMN rtb_id; 

谢谢

没有锁不可能。不过,您可以使用相对较少的短期强锁来实现。

ALTER TABLE 目前将占用排他锁很长一段时间,因为它进行了完全 table 重写。

相反,您需要:

  • ALTER TABLE sites ADD COLUMN rtb_id_new varchar[]
  • 创建一个 BEFORE INSERT OR UPDATE ... FOR EACH ROW 触发器,为每一行设置 NEW.rtb_id_new := string_to_array(NEW.rtb_id,' ')
  • 分批,UPDATE sites SET rtb_id_new = string_to_array(rtb_id,' ')
  • 填充所有值后 VACUUM sites; 然后 ALTER TABLE sites ALTER COLUMN rtb_id_new NOT NULL。这将需要足够长的独占锁来进行顺序扫描,所以它不会超快。在 PostgreSQL 9.5 上,获取的锁较弱并且不会停止 SELECTs.
  • 建立索引CONCURRENTLY
  • ALTER TABLE sites DROP COLUMN rtb_id; ALTER TABLE sites RENAME COLUMN rtb_id_new TO rtb_column;
  • 如果您需要添加任何 UNIQUE 约束,请将它们添加 USING 已构建的索引以最小化锁定持续时间。

这不是完全无锁的。特别是 NOT NULL 约束会受到伤害,因为 PostgreSQL(还)不知道如何将 NOT NULL 约束添加为 NOT VALID 然后验证它。