🛠️ UPDATE меняет одно поле. Почему HOT почти не срабатывает?
Условная статистика:
n_tup_upd = 18 400 000 n_tup_hot_upd = 920 000 n_dead_tup = 3 700 000
При UPDATE PostgreSQL создаёт новую версию строки. HOT позволяет не добавлять для неё записи в обычные индексы, но нужны два условия:
— обновление не меняет данные, на которые ссылаются обычные индексы; — новая версия помещается на той же heap-странице.
Например:
UPDATE orders SET processing_status = 'completed' WHERE id = :id;
Если processing_status используется обычным, составным, partial или expression index, изменение обычно исключает HOT.
Исключение — summarizing indexes: в основной поставке PostgreSQL это BRIN. Они не запрещают HOT тем же способом, хотя их сводные данные могут обновляться.
Если индекс обновлять не нужно, остаётся второй вопрос: хватает ли места на исходной странице.
Более низкий table fillfactor оставляет запас и может повысить вероятность HOT. Но это не гарантия: менее плотное размещение увеличивает число страниц, а изменение параметра само по себе не переразмещает все существующие строки.
Что проверить:
— какие запросы создают основной поток UPDATE; — какие данные используются индексами; — долю n_tup_hot_upd в n_tup_upd; — при доступности — n_tup_newpage_upd; — fillfactor и размеры отношений в динамике; — сопоставимый интервал статистики.
n_dead_tup — оценка, а не точное измерение bloat. VACUUM освобождает место dead versions для повторного использования, но не превращает будущие обновления в HOT автоматически.
Вывод: низкая доля HOT — начало диагностики, а не команда удалить индекс, снизить fillfactor или чаще запускать VACUUM.
🔹🔹🔹🔹