暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL特性矩阵解析系列29之Visibility Map for Vacuuming

1066

描述

visibility map 减少了vacuum清理死元组的开销,因为死元组清理只需要跟踪需要清理的页面即可。

visibility map  “filenode_vm”文件中记录着表中元组可见性。


VM文件作用

PostgreSQL 8.4版本新增空间映射(FSM)和可见性映射(VM),可见性映射(VM)的引入,代表着VACUUM清理时,不需要遍历每个元组来更新FSM。注:8.4版本到8.2版本之间VACUUM是需要遍历所有元组后,来更新FSM文件的。


可见性映射

每一个堆关系都有一个可见性映射(VM)用来跟踪哪些页面 只包含已知对所有活动事务可见的元组,它也跟踪哪些页面只包含 未被冻结的元组。它伴随着主关系数据被存储在一个独立的关系分支中, 以该关系的文件节点号加上一个_vm后缀来命名。例如, 如果一个关系的文件节点为12345,其VM被存储在名为12345_vm的文件中, 该文件域主关系文件在同一个目录中。注意索引没有VM。


可见性映射仅为每个堆页面存储两个位。第一位如果被设置, 表示该页面上的元组都是可见的,或者换句话说该页面不含有 任何需要被清理的元组。这些信息也可以被index-only scans用来只依靠索引元组回答查询。第二位如果 被设置,表示该页面上的元组都已经被冻结。这也意味着防回卷 清理操作也不需要重新访问该页面。


该映射是保守的,我们可以确定不论何时一个位被设置,那就说明条件为真,但是如果一个位没有被设置,它可能为真也可能不为真。可见性映射的位只会被清理操作设置,但是可以被任何在页面上进行的数据修改操作清除。


pg_visibility实验

pg_visibility
模块提供了一种方式来检查一个表的可见性映射(VM)以及页级别的可见性信息。它还提供了函数来检查可见性映射的完整性以及强制重建可见性映射。

有三个不同的位被用来存储有关页级别可见性的信息。可见性映射中的“全部可见”位表示一个关系的对应页面上的所有元组对每一个当前和未来事务都可见。可见性映射中的“全部冻结”位表示该页上的每一个元组都被冻结, 也就是说直到在那个页面上对一个元组进行插入、更新、 删除或者锁定之前都不需要用 vacuum 对该页面进行修改。页面头部的PD_ALL_VISIBLE
位具有和可见性映射中“全部可见”位相同的含义, 但是它存储在数据页面本身中而不是存储在单独的数据结构中。这两个位通常是相互一致的, 但是有时在崩溃恢复后会出现页面的“全部可见”位被设置而可见性映射位被清除的情况, 由于在pg_visibility
检查了可见性映射之后, 且在它检查数据页面之前发生了修改,报告的值也会不一致。任何导致数据损坏的事件也可能导致这些位不一致。

显示有关PD_ALL_VISIBLE
的信息的函数代价比那些查看可见性映射的函数要高很多,因为它们必须读取关系的数据块而不是只读取(小很多的)可见性映射。类似地,检查关系的数据块的函数也很昂贵。

postgres=# create table test(id int);
CREATE TABLE
postgres=# insert into test(id) values(1);
INSERT 0 1
postgres=# insert into test(id) values(1);
INSERT 0 1
postgres=# insert into test(id) values(1);
INSERT 0 1
postgres=# insert into test(id) values(1);
INSERT 0 1
postgres=# insert into test(id) values(1);
INSERT 0 1
postgres=# select pg_relation_filenode('test');
pg_relation_filenode
----------------------
16384
(1 row)


postgres=# select pg_relation_filepath('test');
pg_relation_filepath
----------------------
base/13214/16384
(1 row)


postgres=# vacuum test;
VACUUM
postgres@pgexp1-> ll 13214/16384*
-rw-------. 1 postgres postgres 8.0K Dec 5 20:29 13214/16384
-rw-------. 1 postgres postgres 24K Dec 5 20:31 13214/16384_fsm
-rw-------. 1 postgres postgres 8.0K Dec 5 20:31 13214/16384_vm


postgres=# create extension pg_visibility;
CREATE EXTENSION
postgres=# \dx
List of installed extensions
Name | Version | Schema | Description
---------------+---------+------------+----------------------------------------------------------------
pg_visibility | 1.2 | public | examine the visibility map (VM) and page-level visibility info
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
(2 rows)


1.pg_visibility_map(relation regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean) returns record
为给定关系的给定块返回其在可见性映射中的“全部可见”和“全部冻结”位。
postgres=# select pg_visibility_map('test'::regclass, 0);
pg_visibility_map
-------------------
(t,f)
(1 row)
t表示所有可见。


2.pg_visibility(relation regclass, blkno bigint, all_visible OUT boolean, all_frozen OUT boolean, pd_all_visible OUT boolean) returns record
为给定关系的给定块返回其在可见性映射中的“全部可见”和“全部冻结”位,外加块的PD_ALL_VISIBLE位。
postgres=# select pg_visibility('test'::regclass, 0);
pg_visibility
---------------
(t,f,t)

3.pg_visibility_map(relation regclass, blkno OUT bigint, all_visible OUT boolean, all_frozen OUT boolean) returns setof record
为给定关系的每一块返回其在可见性映射中的“全部可见”和“全部冻结”位。


4.pg_visibility(relation regclass, blkno OUT bigint, all_visible OUT boolean, all_frozen OUT boolean, pd_all_visible OUT boolean) returns setof record
为给定关系的每一块返回其在可见性映射中的“全部可见”和“全部冻结”位,外加每一块的PD_ALL_VISIBLE位。


5.pg_visibility_map_summary(relation regclass, all_visible OUT bigint, all_frozen OUT bigint) returns record
根据可见性映射返回关系中“全部可见”页面和“全部冻结”页面的数量。
postgres=# select pg_visibility_map_summary('test'::regclass);
pg_visibility_map_summary
---------------------------
(1,0)
(1 row)


6.pg_check_frozen(relation regclass, t_ctid OUT tid) returns setof tid
返回存储在可见性映射中被标为“全部冻结”的页面中的非冻结元组的 TID。如果这个函数返回一个非空的 TID 集合,则可见性映射已经损坏。
postgres=# select pg_check_frozen('test'::regclass);
pg_check_frozen
-----------------
(0 rows)


7.pg_check_visible(relation regclass, t_ctid OUT tid) returns setof tid
返回存储在可见性映射中标记为全部可见的页面中的非全部可见元组的TID。如果此函数返回非空的一组TID,则可见性映射已损坏。


8.pg_truncate_visibility_map(relation regclass) returns void
为给定关系截断可见性映射。如果您认为该关系的可见性映射已损坏并希望强制重建它, 则该函数非常有用。在这个函数被执行后,在给定关系上进行的第一次VACUUM 将会扫描关系中的每一个页面并且重建可见性映射。(在完成之前, 查询会将可见性映射看做包含的全是零。)


参考

https://wiki.postgresql.org/images/8/81/FSM_and_Visibility_Map.pdf

文章转载自CP的PostgreSQL厨房,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论