文档章节

透过pageinspect了解PostgreSQl中的page

PGSmith
 PGSmith
发布于 2015/12/31 17:05
字数 1526
阅读 629
收藏 3
点赞 0
评论 0
        博客 PostgreSQL的Page分析记录 有过对page的 大体介绍,可以参看之前的blog,下面主要通过插件 pageinspect 向大家进行介绍。

        在此之前需要了解的名词:
        page,物理文件的单位,默认大小为8K。
        tuple,PG中物理行。
        xid,事务号,执行操作时的顺序id。

        pageinspect里边有三个函数是本文用到的,他们分别是:
        a.get_raw_page,根据参数表明、数据文件类型(main、fsm、vm)以及page位置,将当前表文件中的page内容返回。还有一个函数于此同名,只有两个参数,是将第二个参数省略,直接使用'main'。
        b.page_header,参数是函数get_raw_page的返回值,返回值是将本page结构中的PageHeaderData详细信息
        c.heap_page_items,参数是函数get_raw_page的返回值,返回值是将page内的项指针(ItemIddata)以及HeapTupleHeaderData的详细信息。

        下面通过例子来对page的PageHeaderDataItemIddata和HeapTupleHeaderData进行说明
        a.建表mvcc

[postgres@localhost bin]$ ./psql 
psql (9.4.5)
Type "help" for help.

postgres=# create table mvcc(id int);
CREATE TABLE
postgres=# insert into mvcc values (1),(2);
INSERT 0 2

         b.PageHeaderData

postgres=# select * from page_header(get_raw_page('mvcc', 'main', 0));
    lsn    | checksum | flags | lower | upper | special | pagesize | version | p
rune_xid 
-----------+----------+-------+-------+-------+---------+----------+---------+--
---------
 0/300F4D8 |        0 |     0 |    32 |  8128 |    8192 |     8192 |       4 |  
       0
(1 row)
        这是表mvcc的PageHeaderData信息,现在比对源码对各个字段进行解释:
typedef struct PageHeaderData
{
	/* XXX LSN is member of *any* block, not only page-organized ones */
	PageXLogRecPtr pd_lsn;		/* LSN: next byte after last byte of xlog
								 * record for last change to this page */
	uint16		pd_checksum;	/* checksum */
	uint16		pd_flags;		/* flag bits, see below */
	LocationIndex pd_lower;		/* offset to start of free space */
	LocationIndex pd_upper;		/* offset to end of free space */
	LocationIndex pd_special;	/* offset to start of special space */
	uint16		pd_pagesize_version;
	TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
	ItemIdData	pd_linp[1];		/* beginning of line pointer array */
} PageHeaderData;
        pg_lsn:记录最后一次对page修改的xlog记录id。
        pg_checksum:页面的校验和,主要是通过函数pg_checksum_block函数生成的,0也是有效地,参数为PageHeaderData和BLCKSZ(page's size)。当校验和验证失败,即认为当前页面无效。
        pg_flags:page的flags,具体值为,可以叠加:
#define PD_HAS_FREE_LINES	0x0001		/* are there any unused line pointers? */
#define PD_PAGE_FULL		0x0002		/* not enough free space for new
										 * tuple? */
#define PD_ALL_VISIBLE		0x0004		/* all tuples on page are visible to
										 * everyone */

#define PD_VALID_FLAG_BITS	0x0007		/* OR of all valid pd_flags bits */
        pg_lower和pg_upper:最后一个项指针的位置和最新的tuple位置。主要进行查找空闲位置,进行插入工作。
        pg_special:page预留的位置,可以存储索引等信息。
        pg_pagesize_version:page大小以及当前版本。page大小可以通过configure进行设置。version的意思是
/*
 * Page layout version number 0 is for pre-7.3 Postgres releases.
 * Releases 7.3 and 7.4 use 1, denoting a new HeapTupleHeader layout.
 * Release 8.0 uses 2; it changed the HeapTupleHeader layout again.
 * Release 8.1 uses 3; it redefined HeapTupleHeader infomask bits.
 * Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and
 *		added the pd_flags field (by stealing some bits from pd_tli),
 *		as well as adding the pd_prune_xid field (which enlarges the header).
 *
 * As of Release 9.3, the checksum version must also be considered when
 * handling pages.
 */
          pg_prune_xid:一般是最后一次删除或者更新的xid。

        pg_linp:项指针。
        c.ItemIddata

postgres=# select lp,lp_off,lp_flags,lp_len from heap_page_items(get_raw_page('mvcc', 'main', 0));
 lp | lp_off | lp_flags | lp_len 
----+--------+----------+--------
  1 |   8160 |        1 |     28
  2 |   8128 |        1 |     28
(2 rows)
        这是表mvcc的项指针的信息,一样通过结合源码进行介绍:
typedef struct ItemIdData
{
	unsigned	lp_off:15,		/* offset to tuple (from start of page) */
				lp_flags:2,		/* state of item pointer, see below */
				lp_len:15;		/* byte length of tuple */
} ItemIdData;
        lp:这是插件自己定义的列,在源码中其实没有,这个是项指针的顺序。
        lp_off:tuple在page中的位置。
        lp_flags:tuple的flags,具体为
#define LP_UNUSED		0		/* unused (should always have lp_len=0) */
#define LP_NORMAL		1		/* used (should always have lp_len>0) */
#define LP_REDIRECT		2		/* HOT redirect (should have lp_len=0) */
#define LP_DEAD			3		/* dead, may or may not have storage */
        lp_len: HeapTupleHeaderData 的长度+Oid的长度(8,因为要数据对齐,所以在这里会比原来预计的多4)。

        d.HeapTupleHeaderData

postgres=# select * from heap_page_items(get_raw_page('mvcc', 'main', 0));
 lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infom
ask2 | t_infomask | t_hoff | t_bits | t_oid 
----+--------+----------+--------+--------+--------+----------+--------+--------
-----+------------+--------+--------+-------
  1 |   8160 |        1 |     28 |   1831 |      0 |        0 | (0,1)  |        
   1 |       2048 |     24 |        |      
  2 |   8128 |        1 |     28 |   1831 |      0 |        0 | (0,2)  |        
   1 |       2048 |     24 |        |      
(2 rows)
         同样结合源码进行介绍:
typedef struct HeapTupleFields
{
	TransactionId t_xmin;		/* inserting xact ID */
	TransactionId t_xmax;		/* deleting or locking xact ID */

	union
	{
		CommandId	t_cid;		/* inserting or deleting command ID, or both */
		TransactionId t_xvac;	/* old-style VACUUM FULL xact ID */
	}			t_field3;
} HeapTupleFields;

typedef struct DatumTupleFields
{
 int32		datum_len_;		/* varlena header (do not touch directly!) */


 int32		datum_typmod;	/* -1, or identifier of a record type */


 Oid			datum_typeid;	/* composite type OID, or RECORDOID */


 /*
 * Note: field ordering is chosen with thought that Oid might someday
 * widen to 64 bits.
 */
} DatumTupleFields;

struct HeapTupleHeaderData
{
	union
	{
		HeapTupleFields t_heap;
		DatumTupleFields t_datum;
	}			t_choice;

	ItemPointerData t_ctid;		/* current TID of this or newer tuple */

	/* Fields below here must match MinimalTupleData! */

	uint16		t_infomask2;	/* number of attributes + various flags */

	uint16		t_infomask;		/* various flag bits, see below */

	uint8		t_hoff;			/* sizeof header incl. bitmap, padding */

	/* ^ - 23 bytes - ^ */

	bits8		t_bits[1];		/* bitmap of NULLs -- VARIABLE LENGTH */

	/* MORE DATA FOLLOWS AT END OF STRUCT */
};
        xmin和xmax是插入、删除和更新时的事务ID,插入时会在xmin内写入当前事务ID,当删除时就会在xmax写入当前事务ID。更新是进行删除后再插入。
        t_cid:这个是指一个事务内的命令ID,每个事务都是从0开始。
        t_ctid:这个是指物理ID,结构如下:
typedef struct ItemPointerData
{
	BlockIdData ip_blkid;
	OffsetNumber ip_posid;
}

typedef struct BlockIdData
{
	uint16		bi_hi;
	uint16		bi_lo;
} BlockIdData;
        存储的为bi_hi(文件号) << 16 | bi_lo(page号),来获取磁盘顺序,ip_posid是在page的中序号。以此来准确定位数据。
        t_infomask2:表字段的个数以及一些flags,flags如下:
#define HEAP_NATTS_MASK			0x07FF	/* 11 bits for number of attributes */
/* bits 0x1800 are available */
#define HEAP_KEYS_UPDATED		0x2000	/* tuple was updated and key cols
										 * modified, or tuple deleted */
#define HEAP_HOT_UPDATED		0x4000	/* tuple was HOT-updated */
#define HEAP_ONLY_TUPLE			0x8000	/* this is heap-only tuple */

#define HEAP2_XACT_MASK			0xE000	/* visibility-related bits */
         t_infomask:tuple的flags,如下:
#define HEAP_HASNULL			0x0001	/* has null attribute(s) */
#define HEAP_HASVARWIDTH		0x0002	/* has variable-width attribute(s) */
#define HEAP_HASEXTERNAL		0x0004	/* has external stored attribute(s) */
#define HEAP_HASOID				0x0008	/* has an object-id field */
#define HEAP_XMAX_KEYSHR_LOCK	0x0010	/* xmax is a key-shared locker */
#define HEAP_COMBOCID			0x0020	/* t_cid is a combo cid */
#define HEAP_XMAX_EXCL_LOCK		0x0040	/* xmax is exclusive locker */
#define HEAP_XMAX_LOCK_ONLY		0x0080	/* xmax, if valid, is only a locker */

 /* xmax is a shared locker */
#define HEAP_XMAX_SHR_LOCK	(HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)

#define HEAP_LOCK_MASK	(HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \
						 HEAP_XMAX_KEYSHR_LOCK)
#define HEAP_XMIN_COMMITTED		0x0100	/* t_xmin committed */
#define HEAP_XMIN_INVALID		0x0200	/* t_xmin invalid/aborted */
#define HEAP_XMIN_FROZEN		(HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)
#define HEAP_XMAX_COMMITTED		0x0400	/* t_xmax committed */
#define HEAP_XMAX_INVALID		0x0800	/* t_xmax invalid/aborted */
#define HEAP_XMAX_IS_MULTI		0x1000	/* t_xmax is a MultiXactId */
#define HEAP_UPDATED			0x2000	/* this is UPDATEd version of row */
#define HEAP_MOVED_OFF			0x4000	/* moved to another place by pre-9.0
        t_hoff: HeapTupleHeaderData长度,如果有Oid会增加4,但由于受到对齐的影响,会增加8。
        t_bits:具体数据,可以参照 PostgreSQL的基础数据类型分析记录

© 著作权归作者所有

共有 人打赏支持
PGSmith

PGSmith

粉丝 91
博文 54
码字总数 59729
作品 0
济南
后端工程师
PostgreSQL 垃圾版本引入的索引扫描性能下降诊断

标签 PostgreSQL , 索引 , 多版本 , 垃圾版本 , pageinspect 背景 首先介绍几个背景知识,由于这些背景知识的存在,所以在某些情况下索引扫描的性能可能会出现一些问题或抖动。 导致性能下降...

德哥
04/18
0
0
PostgreSQL 数据库多列复合索引的字段顺序选择原理

标签 PostgreSQL , 多列索引 , 复合索引 , 驱动列 , 顺序 , 等值查询 , 范围扫描 , 离散值 , 连续值 , 单列索引 , bitmap index scan 背景 当需要创建多列复合索引时,应该使用什么样的顺序呢...

德哥
04/18
0
0
PostgreSQL 数据库初体验

高强,“DBA+济南群”联合发起人。现就职于山东华鲁科技发展股份有限公司。擅长Oracle、AIX、Linux、PostgreSQL和DB2等产品的实施、运维和故障处理。曾是一名存储工程师,负责实施存储、双机...

高强
2015/10/15
0
0
PostgreSQL Freeze 风暴预测续 - 珍藏级SQL

标签 PostgreSQL , Freeze , 风暴 背景 PostgreSQL 目前默认的存储引擎,事务可见性需要依赖行头的事务号,因为事务号是32位的,会循环使用。 在一条记录产生后,如果再次经历了20亿个事务,...

德哥
05/06
0
0
在CentOS上编译安装PostgreSQL

第一步:准备阶段 获取必需软件包: CentOS中查看是否安装了某个软件的命令:rpm -qa | grep 软件名。 which命令可查看某个软件的安装路径。 使用 yum install 包名 来安装软件包。 1.GNU ma...

恒者
2014/01/01
0
3
PostgreSQL 数据离散性 与 索引扫描性能(btree and bitmap index scan)

标签 PostgreSQL , 数据离散性 , 扫描性能 , 重复扫 , bitmap index scan , 排序扫描 背景 PostgreSQL中数据的扫描方法很多,常见的有: 1、全表顺序扫描(seqscan) 2、索引+回表扫描(index ...

德哥
04/18
0
0
PostgreSQL 11 preview - Allow on-line enabling and disabling of data checksums

标签 PostgreSQL , checksum , online modify , pgverifychecksums , pgenabledatachecksums , pgdisabledatachecksums 背景 PostgreSQL的数据文件是以数据块组织的,由于数据块可能比文件系......

德哥
05/06
0
0
Oracle DBA 增值 PostgreSQL,Greenplum 学习计划

标签 PostgreSQL , Oracle , Greenplum 背景 去O很大程度上是国家层面的战略考虑,比如斯诺登事件,最近贸易战的“中兴”事件,使得去O成为一个不可不做的事情。 但是去O喊了若干年,并没有真...

德哥
05/06
0
0
给PostgreSQL爱好者的参考资料

出处 http://blog.163.com/digoal@126/blog/static/163877040201172183022203/ 给PostgreSQL爱好者的参考资料 2011-08-21 08:32:39| 分类: PostgreSQL|举报|字号 订阅 推荐书籍: 概念书籍:......

3444542
06/26
0
0
PostgreSQL9.x集簇备份pg_basebackup

从postgresql 9版本开始增添了pgbasebackup客户端工具程序,它可以用来备份整个数据库集簇,可以用作流复制的基础备份的一个更方便的方式。 pgbasebackup语法详见:http://www.postgresql.o...

YuanyuanL
2015/08/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Mybaties入门介绍

Mybaties和Hibernate是我们在Java开发中应用的比较多的两个ORM框架。当然,目前Mybaties正在慢慢取代Hibernate,这是因为相比较Hibernate而言Mybaties性能更好,响应更快,更加灵活。我们在开...

王子城
昨天
0
0
编程学习笔记之python深入之装饰器案例及说明文档[图]

编程学习笔记之python深入之装饰器案例及说明文档[图] 装饰器即在不对一个函数体进行任何修改,以及不改变整体的原本意思的情况下,增加函数功能的新函数,因为这个新函数对旧函数进行了装饰...

原创小博客
昨天
0
0
流利阅读笔记33-20180722待学习

黑暗中的生物:利用奇技淫巧快活生存 Daniel 2018-07-22 1.今日导读 如果让你在伸手不见五指的黑暗当中生存,你能熬过几天呢?而大千世界,无奇不有。在很多你不知道的角落,有些生物在完全黑...

aibinxiao
昨天
2
0
Hystrix降级逻辑中如何获取触发的异常

通过之前Spring Cloud系列教程中的《Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)》一文,我们已经知道如何通过Hystrix来保护自己的服务不被外部依赖方拖垮的情况。但是实际...

程序猿DD
昨天
0
0
gin endless 热重启

r := gin.New()r.GET("/", func(c *gin.Context) {c.String(200, config.Config.Server.AppId)})s := endless.NewServer(":8080", r)s.BeforeBegin = func(add string) ......

李琼涛
昨天
0
0
JAVA模式之代理模式

平时一直在用spring,spring中最大的特效IOC和AOP,其中AOP使用的就是代理模式.闲着无聊,随手写了一个代理模式,也记录下代理模式的实现Demo. 比如现在有一个场景是:客户想要增加一个新的功能,...

勤奋的蚂蚁
昨天
0
0
ES15-JAVA API 索引管理

1.创建连接 创建连接demo package com.sean.esapi.client;import java.net.InetSocketAddress;import org.elasticsearch.action.get.GetResponse;import org.elasticsearch.clien......

贾峰uk
昨天
0
0
单点登录的设计,从单域名到多域名(经验分享)

个人实践总结,最初的的需求,多个产品线都在同一个根域名下面。 独立的用户中心分离,单独负责用户登录和用户信息获取、变更等处理逻辑。 第一步,用户登录成功,分配给用户一个memToken(令...

小海bug
昨天
0
0
合格前端第十二弹-TypeScript + 大型项目实战

写在前面 TypeScript 已经出来很久了,很多大公司很多大项目也都在使用它进行开发。上个月,我这边也正式跟进一个对集团的大型运维类项目。 项目要做的事情大致分为以下几个大模块 一站式管理...

qiangdada
昨天
3
0
gradle学习笔记

相关文档 适合新手的 gradle 自学教程合集 Gradle教程

OSC_fly
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部