A heap-only-tuple (HOT) update writes the new row version on the same page as the old one and touches no index at all: the old version’s line pointer redirects to the new one. Two conditions, both required: the update changes no indexed column, and the page has free space. When either fails, the new version lands on another page and every index on the table gets a new entry. On update-heavy tables the HOT rate (n_tup_hot_upd vs n_tup_upd) decides the write amplification.
DEMO — one heap page, 3 indexes8 slots per page
live
live
live
live
live
live
live
live
fillfactor100
default 100 · below 100 leaves page space for HOT updates (resets the page)
HOT chains are pruned by ordinary reads, not only by vacuum, which is why a hot page can stay small without ever being vacuumed. Postgres 16 relaxed the index condition for summarizing (BRIN) indexes.