Postgresql管理系列-第七章Heap Only Tuple and Index-Only Scans

本章介绍与索引扫描相关的两个功能, 即Heap Only Tuple和Index-Only Scans。

7.1. Heap Only Tuple (HOT)

HOT是在8.3版中引入的, 当更新的行存储在旧行所在的page时,可以有效地使用索引和表的页。HOT有效的减少了vacuum操作。
源码目录README.HOT描述了HOT的细节。 本章简要介绍了HOT。首先, 7.1.1章节介绍了如何在没有HOT的情况下更新行。接下来,7.1.2部分介绍了HOT是如何执行的。

7.1.1. 更新没有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个tuples;id为"1000"的最后一个tuples存储在表的第5个page。最后一个tuples指向相应的索引元组,其中的键为"1000",其tid为"(5,1)"。请参阅图 7.1(a)。

图7.1. 更新没有HOT的行
在这里插入图片描述

我们考虑如何在没有HOT的情况下更新最后一个tuples

testdb=# UPDATE tbl SET data = 'B' WHERE id = 1000;

在这种情况下, PostgreSQL不仅会在表page中插入新的tuples, 还会在索引page中插入新的索引tuples。请参阅图 7.1(b)。
索引tuples的插入会占用索引页的空间, 并且索引tuples的插入和vacuum成本都很高。HOT减少了这些问题的影响。

7.1.2. HOT如何执行

HOT行更新的时候,如果更新的行存储在旧行所在的page时,Postgresql不需要插入相应的index tuples,并且分别设置HEAP_HOT_UPDATED bit和HEAP_ONLY_TUPLE bit为旧tuples和新tuples的t_informask2,参照图7.2和7.3

图 7.2. 更新HOT行
在这里插入图片描述

例如, 在这种情况下, “Tuple_1” 和 "Tuple_2"分别设置HEAP_hot_upeded和HEAP_ONLY_TUPLE的bit位。

此外, 无论修剪情况如何,都会使用HEAP_hot_update和HEAP_ONLY_TUPLE bit位执行碎片整理。如下图所示

图 7.3. HEAP_HOT_UPDATED和HEAP_ONLY_TUPLE bits
在这里插入图片描述

如下, 本文描述了PostgreSQL如何使用HOT更新后的tuples索引扫描访问更新的tuples。请参阅图 7.4(a)。

图 7.4. 修剪行指针
在这里插入图片描述

(1) 找出指向目标tuples的索引tuples
(2) 访问从索引tuples中获取的行指针 “[1]”
(3) 读"Tuple_1"
(4) 通过"Tuple_1"的ctid读"Tuple_2"

在这种情况下, PostgreSQL读取两个元组, “Tuple_1” 和 “Tuple_2”, 并通过第5章中描述的并发控制机制来确定哪个是可见的。
但是, 如果删除表页中的dead tuples, 则会出现问题。例如, 在图7.4(a)中, 如果删除"Tuple_1", 因为它是dead tuple, 则无法从索引中访问"Tuple_2"。

为了解决此问题, 在适当的时候, PostgreSQL将指向旧tuple的行指针重定向到指向新tuple的行指针。在 PostgreSQL中,此处理称为修剪。图 7.4(b)描述了PostgreSQL 在修剪后如何访问更新的tuples。

(1) 查找index tuple
(2) 访问从索引tuples中指向的行指针 “[1]”
(3) 通过重定向的行指针访问指向"Tuple_2"的行指针"[2]"
(4) 从指向point"[2]“的point读取"Tuple_2”

如果可能发生, 在执行SQL命令 (如 SELECT,UPDATE,INSERT和DELETE) 时,将执行修剪处理。本章没有介绍确切的执行时间, 因为它非常复杂。详细信息。

如果可能, 在修剪过程中,PostgreSQL会在适当的时间删除dead tuples。在PostgreSQL官方文档中, 此处理称为碎片整理。图7.5描述了由HOT引发的碎片整理。

图 7.5. dead tuples碎片整理
在这里插入图片描述
请注意, 碎片整理的成本低于正常的VACUM处理成本,因为碎片整理不涉及删除索引元组。
因此, 使用HOT可以减少索引也和表页的消耗;这也减少了VACUUM处理的tuples。因此, HOT对性能有很好的影响, 因为它最终减少了在update和vacuum的时候index tuples的插入次数。

没有HOT的示例

为了清楚地了解 HOT的运行情况, 这个示例描述了没有HOT的情况
当更新后的tuples没有存储在old tuples的同一页中时, 指向该tuple的索引tuple也会插入到索引页中。请参阅图 7.6(a)
当索引tuple的键值更新时, 将在索引页中插入新的索引tuple。请参阅图 7.6(b)

图7.6.没有HOT的示例
在这里插入图片描述

与HOT相关的统计数据

pg_stat_all_tables为每个表提供了统计值,也可以查看https://github.com/s-hironobu/pg_stats插件

7.2. Index-Only Scans

为了降低I/O(输入/输出)成本, 当SELECT语句的所有数据都包含在索引键中时, 索引扫描(通常称为 index-only access)直接使用索引键,而不访问相应的表页。所有商业RDBMS都提供此项技术 ,如DB2和oracle.Postgresql从9.2版本开始引入。

下面的示例描述Postgresql中index-only scans是如何运行的

假设示例如下:
1.表结构
我们有一个表"tbl",其定义如下所示:

testdb=# \d tbl
      Table "public.tbl"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
 name   | text    | 
 data   | text    | 
Indexes:
    "tbl_idx" btree (id, name)

2.索引
表"tbl"有一个索引"tbl_idx", 它由两列组成:“id"和"name”。

3.tuples
“tbl"已经插入了以下tuples
“Tuple_18”,其id为"18”, 名称为"Queen",存储在第0号页面中。
“Tuple_19”,其id为"19", 名称为"BOSTON", 存储在第1号页面中。

4.可见性
第0号页中的所有tuples始终可见;第1号页中的元组并不总是可见。请注意, 每个页面的可见性存储在相应的visibility map中, 第6.2节中描述了visibility map.

让我们探讨一下以下select命令执行的时候,Postgresql是如何去取tuples的

testdb=# SELECT id, name FROM tbl WHERE id BETWEEN 18 and 19;
 id |  name   
----+--------
 18 | Queen
 19 | Boston
(2 rows)

查询从表的两列获取数据:“id"和"name”, 索引"tbl_idx"包含这些列。因此,在使用索引扫描时, 乍一看似乎并不需要访问表页面,因为索引tuples包含了必要的数据。然而, 事实上, PostgreSQL原则上必须检查tuples的可见性,并且索引tuples没有相关事务的任何信息,例如,heap tuples的t_xmin和t_xmax, 在第5.2节中所述。因此, PostgreSQL必须访问表数据, 以检查索引tuples中数据的可见性。这就像把马车放在马面前。

为了避免这种尴尬,PostgreSQL使用表的visibility map。如果存储在一个页面中的所有tuples都可见, PostgreSQL将使用索引tuples的键, 并且不访问从索引tuples指向的表页来检查其可见性;除此之外,PostgreSQL会读取索引tuples指向的表tuples,并检查tuples的可见性,这是一般常见的过程。

在此示例中, 不需要访问"Tuple_18", 因为存储"Tuple_18"的第0页是可见的, 也就是说,在第0页中包括Tuple_18的所有tuples都可见。相反, 需要访问"Tuple_19" 来处理并发控制,因为第1页的可见性是不可见。参见图7.7。

图7.7. Index-Only Scans如何执行
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值