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

时间:2015-09-28 19:33:00

标签: arrays postgresql indexing locking

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

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; 

由于

1 个答案:

答案 0 :(得分:1)

It is not possible to do it without locks. You can do it with relatively few short-lived strong locks, though.

The ALTER TABLE will take an exclusive lock for a long while at the moment because it does a full table rewrite.

Instead you'll need to:

  • ALTER TABLE sites ADD COLUMN rtb_id_new varchar[]
  • Create a 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,' ')
  • Once all values are populated VACUUM sites; then ALTER TABLE sites ALTER COLUMN rtb_id_new NOT NULL. This will take an exclusive lock for long enough to do a sequential scan, so it's not going to be super-fast. On PostgreSQL 9.5 the lock taken is weaker and won't stop SELECTs.
  • Build your indexes CONCURRENTLY
  • ALTER TABLE sites DROP COLUMN rtb_id; ALTER TABLE sites RENAME COLUMN rtb_id_new TO rtb_column;
  • If you need to add any UNIQUE constraints, add them USING the indexes already built to minimise lock durations.

This isn't totally lock-free. In particular the NOT NULL constraint will hurt because PostgreSQL doesn't (yet) know how to add a NOT NULL constraint as NOT VALID then validate it.