Hi,

I'm trying to understand whether the following behavior is expected in
PostgreSQL.

Environment

- PostgreSQL 15.17
 - Declarative partitioning
 - B-tree indexes

According to the documentation, increasing the length of a varchar column
does not require a table rewrite.

PostgreSQL: Documentation: 15: ALTER TABLE

However, I observed different behaviors depending on whether the parent
partitioned table has an index referencing the altered column.

========================================================================
 Case 1 - No parent index
 ========================================================================

CREATE TABLE orders
 (
 id bigint,
 order_date date,
 data_field varchar(30),
 PRIMARY KEY (id, order_date)
 ) PARTITION BY RANGE (order_date);

CREATE TABLE orders_p202510
 PARTITION OF orders
 FOR VALUES FROM ('2025-10-01') TO ('2025-11-01');

CREATE INDEX orders_p202510_data_field_idx
 ON orders_p202510(data_field);

ALTER TABLE orders
 ALTER COLUMN data_field TYPE varchar(50);

Observation:

- No heap rewrite occurs.
 - pg_stat_progress_cluster remains empty.
 - pg_stat_progress_create_index remains empty.
 - relfilenode of orders_p202510_data_field_idx remains unchanged.

========================================================================
 Case 2 - Parent partitioned index exists
 ========================================================================

CREATE TABLE orders
 (
 id bigint,
 order_date date,
 data_field varchar(30),
 PRIMARY KEY (id, order_date)
 ) PARTITION BY RANGE (order_date);

CREATE TABLE orders_p202510
 PARTITION OF orders
 FOR VALUES FROM ('2025-10-01') TO ('2025-11-01');

CREATE INDEX idx_orders_data_field
 ON orders(data_field);

ALTER TABLE orders
 ALTER COLUMN data_field TYPE varchar(50);

Observation:

- No heap rewrite occurs.
 - pg_stat_progress_cluster remains empty.
 - pg_stat_progress_create_index reports:

 command = CREATE INDEX
 phase = building index: scanning table

- relfilenode of the child index changes.
 - ALTER TABLE execution time increases proportionally with the child index
size.

========================================================================
 Additional observations
 ========================================================================

I also tested other parent index definitions.

The behavior is the same whether data_field is:

 CREATE INDEX idx1 ON orders(data_field);

or

 CREATE INDEX idx2 ON orders(id) INCLUDE (data_field);

In both cases, child indexes are rebuilt.

On the other hand, if the parent table has no index referencing data_field,
child indexes are left untouched.

>From my testing, the deciding factor appears to be simply the existence of
a parent index that depends on the altered column.

========================================================================
 Questions
 ========================================================================

1. Is this expected behavior?

2. If so, what is the rationale for rebuilding child indexes even though
the heap itself is not rewritten?

3. Is rebuilding triggered simply because a parent partitioned index
depends on the altered column, or is there another internal reason for
doing so?

I searched the documentation and mailing list archives but couldn't find
any discussion describing this specific behavior.

Any clarification would be greatly appreciated.

Thank you.

Reply via email to