Question

I want to alter column data type from float4 to float8 on a table with huge rows count. If I do it in usual path it takes much time and my table blocked for this time. IS any hack to do it without rewrite the table content?

Was it helpful?

Solution

ALTER TABLE ... ALTER COLUMN ... TYPE ... USING ... (or related things like ALTER TABLE ... ADD COLUMN ... DEFAULT ... NOT NULL) requires a full table rewrite with an exclusive lock.

You can, with a bit of effort, work around this in steps:

  • ALTER TABLE thetable ADD COLUMN thecol_tmp newtype without NOT NULL.

  • Create a trigger on the table that, for every write to thecol, updates thecol_tmp as well, so new rows that're created, and rows that're updated, get a value for newcol_tmp as well as newcol.

  • In batches by ID range, UPDATE thetable SET thecol_tmp = CAST(thecol AS newtype) WHERE id BETWEEN .. AND ..

  • once all values are populated in thecol_tmp, ALTER TABLE thetable ALTER COLUMN thecol_tmp SET NOT NULL;.

  • Now swap the columns and drop the trigger in a single tx:

    • BEGIN;
    • ALTER TABLE thetable DROP COLUMN thecol;
    • ALTER TABLE thetable RENAME COLUMN thecol_tmp TO thecol;
    • DROP TRIGGER whatever_trigger_name ON thetable;
    • COMMIT;

Ideally we'd have an ALTER TABLE ... ALTER COLUMN ... CONCURRENTLY that did this within PostgreSQL, but nobody's implemented that. Yet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top