PostgreSQL中,区别由于其多版本的区别特性,当我们进行数据更新时,区别实际上并不是区别直接修改元数据,而是区别通过新插入一行数据来进行间接的更新。而当表上存在索引时,区别由于新插入了数据,区别那么索引必然也需要同步进行更新,区别这在索引较多的区别情况下,对于更新的区别性能影响必然很大。 为了解决这一问题,区别pg从8.3版本开始就引入了HOT(Heap Only Tuple)机制。区别其原理大致为,区别当更新的区别不是索引字段时,我们通过将旧元组指向新元组,而原先的索引不变,仍然指向旧元组,但是我们可以通过旧元组作为间接去访问到新的元组,这样就不用再去更新索引了。 要使用HOT进行更新,需要满足两个前提: 当我们进行HOT更新时,首先是分别设置旧元组的t_informask2标志位为HEAP_HOT_UPDATED和新元组为HEAP_ONLY_TUPLE。 更新如下图所示: 我们更新tuple1为tuple2,分别设置这两行元组的t_informask2标志位,然后tuple1的ctid指向tuple2,而tuple2指向自己。 但是这样存在一个明显的问题,我们都知道pg会定期进行vacuum清理那些死元组,那么我们这里如果通过tuple1去访问tuple2的话,tuple1这个死元组被清理了又该怎么办呢? 所以pg会在合适的时机进行行指针的重定向,将旧元组的行指针指向新元组的行指针,这一过程称为修剪。于是在修剪之后,我们通过HOT机制访问数据便成了这样: 1、通过索引元组找到旧元组的行指针1; 2、通过重定向的行指针1找到行指针2; 3、通过行指针2找到新元组tuple2。 这样即使旧元组tuple1被清理掉也没有影响了。香港云服务器 HOT对应的wal日志实现: 对于HOT的update操作,其wal日志中记录的信息主要是由xl_heap_update结构存储。 如果新的元组存储在 block_id 为 0 的块上,如果不是 XLOG_HEAP_HOT_UPDATE,那么旧的元组将会存储在 block_id 为 1 的块上。反之如果block_id 为 1 的块没有被使用,那么则认为是 XLOG_HEAP_HOT_UPDATE。 前面我们提到了,旧行的行指针会重定向到新行的行指针,这一过程称之为修剪。那么什么时候会发生修剪呢? 一般来说,当我们执行select、update、insert、delete这些命令时均有可能触发修剪,其触发机制大致有两种情况: 除此之外,服务器租用当进行修剪时,还会选择合适的时机进行死元组的清理,这一操作称为碎片整理。碎片整理发生在当我们对元组进行检索时发现空闲空间少于10%时,和修剪不同的是,碎片整理不会发生在insert时,因为该操作并不会检索行。 相较于普通的vacuum操作,碎片清理并不涉及索引元组的清理,开销相对于常规的清理要小很多,是通过PageRepairFragmentation函数来实现的。 这也是为什么HOT要求新旧元组需要在同一个page中,虽然从理论上来说我们可以将行指针的链表指向不同page,但是这样我们便不能使用page-local的操作来进行碎片清理了。 前面我们提到了HOT的前提条件之一就是:更新的列不能是索引列。需要注意,当更新的列是索引列时并不仅仅是会修改该列上的索引,整张表上所有的索引均会被修改。 例子: 创建测试表:1、区别HOT概述
2、HOT实现技术细节
3、何时进行修剪
4、HOT的不足