PostgreSQL HOT与PHOT有哪些区别

发布时间:2025-05-17 00:41:28 作者:益强科技 来源:undefined 浏览量(2) 点赞(1)
摘要:1、HOT概述 PostgreSQL中,由于其多版本的特性,当我们进行数据更新时,实际上并不是直接修改元数据,而是通过新插入一行数据来进行间接的更新。而当表上存在索引时,由于新插入了数据,那么索引必然也需要同步进行更新,这在索引较多的情况下,对于更新的性能影响必然很大

1、HOT概述

PostgreSQL中,由于其多版本的特性,当我们进行数据更新时,实际上并不是直接修改元数据,而是通过新插入一行数据来进行间接的更新。而当表上存在索引时,由于新插入了数据,那么索引必然也需要同步进行更新,这在索引较多的情况下,对于更新的性能影响必然很大。

为了解决这一问题,pg从8.3版本开始就引入了HOT(Heap Only Tuple)机制。其原理大致为,当更新的不是索引字段时,我们通过将旧元组指向新元组,而原先的索引不变,仍然指向旧元组,但是我们可以通过旧元组作为间接去访问到新的元组,这样就不用再去更新索引了。

2、HOT实现技术细节

要使用HOT进行更新,需要满足两个前提:

新的元组和旧元组必须在同一个page中; 索引字段不能进行更新。

当我们进行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。

3、何时进行修剪

前面我们提到了,旧行的行指针会重定向到新行的行指针,这一过程称之为修剪。那么什么时候会发生修剪呢?

一般来说,当我们执行select、update、insert、delete这些命令时均有可能触发修剪,其触发机制大致有两种情况:

上一次进行update时无法在本page找到足够的空间; 当前page上剩余空间小于fill-factor的值,最多小于10%

除此之外,当进行修剪时,还会选择合适的时机进行死元组的清理,这一操作称为碎片整理。碎片整理发生在当我们对元组进行检索时发现空闲空间少于10%时,和修剪不同的是,碎片整理不会发生在insert时,因为该操作并不会检索行。

相较于普通的vacuum操作,碎片清理并不涉及索引元组的清理,开销相对于常规的清理要小很多,是通过PageRepairFragmentation函数来实现的。

这也是为什么HOT要求新旧元组需要在同一个page中,虽然从理论上来说我们可以将行指针的链表指向不同page,但是这样我们便不能使用page-local的操作来进行碎片清理了。

4、HOT的不足

前面我们提到了HOT的前提条件之一就是:更新的列不能是索引列。需要注意,当更新的列是索引列时并不仅仅是会修改该列上的索引,整张表上所有的索引均会被修改。

例子:

创建测试表:

bill=# create table a(id int, c1 int, c2 int, c3 int); CREATE TABLE bill=# insert into a select generate_series(1,10), random()*100, random()*100, random()*100; INSERT 0 10 bill=# create index idx_a_1 on a (id); CREATE INDEX bill=# create index idx_a_2 on a (c1); CREATE INDEX bill=# create index idx_a_3 on a (c2); CREATE INDEX

二维码

扫一扫,关注我们

声明:本文由【益强科技】编辑上传发布,转载此文章须经作者同意,并请附上出处【益强科技】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15687827356
在线客服
嘿,我来帮您!