1.HOT简介
PG从8.3版本开始,实现了HOT的特性,HOT为Heap-Only Tuple updates的缩写,即堆内元组更新,HOT使行更新时,将新记录和旧记录放在同一个页面内,这样就避免了索引元组的修改(索引元组修改很消耗资源),避免了不必要的清理过程。
2.为什么引入HOT
我们知道,PG删除行或更新行不会真正的清除旧的记录,而是将其标记为删除,在事务中不可见,但是数据的变更会影响索引的引用,因为索引的叶块保存的是索引键值(列)和键值所在的块号和偏移量。如下所示
test=# SELECT * FROM index_page('idx_id',1);
itemoffset | htid | dead
------------+-------+------
1 | (0,1) | f
2 | (0,2) | f
3 | (0,3) | f
4 | (0,4) | f
5 | (1,1) | f
(5 rows)
第一列itemoffset是索引记录在本页的偏移量。第二列htid就是索引所指向的数据页的页号和偏移量。(0,1)表示该条索引记录指向的数据页为表0号页面第1条记录,同理(1,1)表示1号页面第1条记录。
在没有HOT之前,一旦行发生更新,新行很有可能在本页面,也可能插入到新的页面上去,无论更新的行是在本页面还是新页面,那么此时原索引的(0,1)记录就无效了,需要为更新的行新增一条新的指针记录。当然,索引页记录也不会删除,会标记为“死亡”,这样频繁的更新不仅仅会造成表数据的膨胀,更严重的是索引数据的膨胀,因此,postgreSQL引入了HOT。
3.HOT的工作原理
引入HOT后,在更新一行时,如果更新的行和旧的行在同一个页面上(可以配置较小的fillfactor参数,给更新留足空间),那么就不会再修改改行的索引记录,而是在旧元组标记为Heap Hot Updated,而同页面内的新行标记为Heap Only Tuple,两个标志位分别保存在自己元组的t_infomask2字段中。
#创建表
test=# drop table hot;
DROP TABLE
test=# create table hot (id int,name varchar(20));
CREATE TABLE
#创建基于ID列的索引
test=# create index ind_id on hot(id);
CREATE INDEX
#插入三行记录
test=# insert into hot values(1,'aaa');
INSERT 0 1
test=# insert into hot values(2,'bbb');
INSERT 0 1
test=# insert into hot values(3,'ccc'