Heap Only Tuples (HOT) PostgreSQL
Для снижения издержек, связанных с изменениями данных, в PostgreSQL реализована оптимизация HOT (Heap Only Tuples).
Её применение возможно при соблюдении следующих условий:
- При изменении не затрагиваются столбцы, задействованные в индексах таблицы (в том числе, в индексах по выражениям и частичных индексах);
- На странице, содержащей старую версию строки, достаточно свободного места для новой.
При соблюдении этих условий оптимизация HOT даёт два преимущества:
- Для представления изменённых строк не нужны новые элементы индекса.
-
Старые версии изменённых строк могут быть полностью удалены в ходе обычной работы, даже во время
SELECT, для этого не нужно периодически выполнять операции очистки. (Это возможно, поскольку индексы не ссылаются на идентификаторы элементов страниц).
Сейчас HOT задействован только тогда, когда в апдейте участвуют только не индексируемые столбцы. Если хотя бы один столбец, участвующий в апдейте входит в индекс, HOT применить нельзя. В этом случае с применением HOT есть несколько проблем. Например, когда по индексу на колонке, которую проапдейтили нужно сделать индекс скан и старая копия строки попадает в предикат скана, а новая — нет. За изменениями в режиме HOT позволяет наблюдать системное представление pg_stat_all_tables.
Более детальную информацию о данном механизме Вы найдете в README.HOT.
Далее дается описание процесса обновления строки без механизма HOT, чтобы наглядно проиллюстрировать проблемы, которые решает данный механизм. Следующий раздел описывает принцип работы HOT.
Обновление строки без HOT
Предположим, что таблица 'tbl' содержит два столбца: 'id' и 'data'; при этом 'id' является первичным ключом таблицы 'tbl'.
testdb=# \d tbl
Table "public.tbl"
Column | Type | Collation | Nullable | Default
-------+---------+-----------+----------+---------
id | integer | | not null |
data | text | | |
Indexes:
"tbl_pkey" PRIMARY KEY, btree (id)
Таблица 'tbl' содержит 1000 кортежей; последний кортеж, чей идентификатор равен 1000, хранится на 5-й странице таблицы. На последний кортеж указывает соответствующий индекс, ключ которого равен 1000, а tid - '(5, 1)'. См. рис. 78(a).
Как происходит обновление последнего кортежа без применения механизма HOT:
testdb=#UPDATEtblSETdata='B'WHEREid=1000;
В этом случае PostgreSQL вставляет в индексную страницу не только новый кортеж, но и новый индексный кортеж. См. рис. 78(b).
Стоит заметить, что затраты на вставку кортежей достаточно велики. HOT невелирует данный нежелательный момент.
Принцип работы HOT
При обновлении строки с помощью HOT, если обновленная строка будет храниться в той же странице таблицы, где хранится старая строка, PostgreSQL не вставляет соответствующий индексный кортеж и устанавливает флаг HEAP_HOT_UPDATED и флаг HEAP_ONLY_TUPLE в поля t_informask2 старого и нового кортежа соответственно. Смотрите рисунки 79 и 80.
В этом случае для Tuple_1 и Nuple_2 устанавливаются флаги HEAP_HOT_UPDATED и HEAP_ONLY_TUPLE соответственно.
Далее приводится описание того, как PostgreSQL получает доступ к обновленным кортежам с помощью индексного сканирования сразу после обновления кортежей с помощью HOT. Смотрите рис. 81(a).
- (1) Найдите индексный кортеж, указывающий на целевой кортеж.
- (2) Перейдите к указателю строки [1], на которую указывает индексный кортеж.
- (3) Прочитайте Tuple_1.
- (4) Прочитайте Tuple_2 с помощью t_ctid Tuple_1.
В данном случае PostgreSQL считывает два кортежа, Tuple_1 и Tuple_2, и решает, какой из них будет видимым, используя механизм управления параллельным доступом, описанном в разделе 5.
Однако удаление “мертвых” кортежей на страницах таблицы приводит к неелательным последствиям - если удалить Tuple_1, поскольку он является “мертвым”, то к Tuple_2 нельзя будет получить доступ из индекса.
Чтобы решить эту проблему, в нужный момент PostgreSQL перенаправляет указатель строки, указывающий на старый кортеж, на указатель строки, указывающий на новый кортеж – рис. 81 b
- (1) Найдите индексный кортеж.
- (2) Перейдите к указателю строки [1], на которую указывает индексный кортеж.
- (3) Перейдите к указателю строки [2], указывающему на Tuple_2.
- (4) Прочитайте Tuple_2, на который указывает указатель строки [2].
Более подробную информацию Вы найдете в файле README.HOT.
PostgreSQL удаляет мертвые кортежи в определенные промежутки времени. Данный процесс называется дефрагментацией. Рис. 82 иллюстрирует дефрагментацию с помощью механизма HOT.
Обратите внимание на то, что стоимость дефрагментации гораздо меньше стоимости операции VACUUM, поскольку дефрагментация не предполагает удаления индексных кортежей.
Примечание: случаи, когда использование механизма HOT невозможно
Для лучшего понимания принципа работы HOT, я опишу случаи, когда использования данного механизма недоступно.
Когда обновленный кортеж хранится на странице, отличной от страницы, на которой хранится старый кортеж, индексный кортеж, указывающий на этот кортеж, также должен быть вставлен в индексную страницу. Смотрите рис. 83 (a).
При обновлении значения ключа индексного кортежа в индексную страницу должен быть вставлен новый индексный кортеж. Смотрите рис. 83 (b).









