Slow Execution of ALTER TABLE on Large Table when changing column type

Last edited: 9/9/2025

If you encounter slow execution of the ALTER TABLE operation on a large table when changing a column data type, consider the following alternative approach.

Alternative Approach:

  1. Add a New Column with the New Type: ALTER TABLE "table_name" ADD COLUMN "new_column_name" new_data_type;

  2. Copy Values from the First Column to the Second: UPDATE "table_name" SET "old_column_name" = "new_column_name"::new_data_type;

  3. Drop the Old Column: ALTER TABLE "table_name" DROP COLUMN "old_column_name";

Why Use This Approach? The long execution time for the ALTER TABLE operation can be attributed to the large size of the table. This segmented approach helps in:

  • Efficiency: The process is more efficient as it avoids prolonged transactions.
  • Minimizing Disruption: Migrating data systematically minimizes the impact on other operations and users.

Additional Recommendations:

  • Set session statement_timeout to 0 to prevent potential transaction timeouts.

  • Monitor currently blocked database transactions during the process using the provided script:

1
create view public.lock_monitor as
2
select
3
coalesce(
4
blockingl.relation::regclass::text,
5
blockingl.locktype
6
) as locked_item,
7
now() - blockeda.query_start as waiting_duration,
8
[blockeda.pid](http://blockeda.pid/) as blocked_pid,
9
blockeda.query as blocked_query,
10
blockedl.mode as blocked_mode,
11
[blockinga.pid](http://blockinga.pid/) as blocking_pid,
12
blockinga.query as blocking_query,
13
blockingl.mode as blocking_mode
14
from
15
pg_locks blockedl
16
join pg_stat_activity blockeda on [blockedl.pid](http://blockedl.pid/) = [blockeda.pid](http://blockeda.pid/)
17
join pg_locks blockingl on (
18
blockingl.transactionid = blockedl.transactionid
19
or blockingl.relation = blockedl.relation
20
and blockingl.locktype = blockedl.locktype
21
)
22
and [blockedl.pid](http://blockedl.pid/) <> [blockingl.pid](http://blockingl.pid/)
23
join pg_stat_activity blockinga on [blockingl.pid](http://blockingl.pid/) = [blockinga.pid](http://blockinga.pid/)
24
and blockinga.datid = blockeda.datid
25
where
26
not blockedl.granted
27
and blockinga.datname = current_database();

Notes: Execute these steps during a maintenance window or low-traffic period to minimize disruption.