zoukankan      html  css  js  c++  java
  • postgresql磁盘存储结构

    1.  Page header24Byte

    1.1.  描述

    记录页头的信息。

    1.2.  get_raw_page函数

    将指定表文件中的页面内容返回,param1:表名,param2main/fsm/vm, param3:第几页

    1.3.  page_header(函数)

    作用:

    返回本页面中的page header信息。param1get_raw_page函数的返回值。

    page的前24字节存储head data

    字段:

           lsn:记录最后一次对页修改的xlog记录

           checksum:页面的校验和,用于判断当前页是否完整

           flags:(指示当前页的状态)

           lower:本页空闲位置的起始指针

           uper:本业空闲位置的结束指针

           special:页预留的位置

           pagesize:页面大小

           version:当前版本

           prune_xid:最后一次删除或更新的xid

           页后面存储的是元组(tuple)信息的数据(表的数据行,一个元组信息就是一行),也就是下一节的page item

    1.4.  图解

    2.  Page item(页内存储的tuple数据)

    一条数据(数据库行)由Item ID + Tuple Header + data(实际数据,由用户写入)组成。

    Item IdPage head存放在一起,存在页的一端,Tuple Header + data 存放在一起,存放在页的另一端。

    1.5.  Item ID(行指针,4字节)

           

    1.6.  Tuple Header(元组头,23字节)

    描述元组数据的数据,描述本条数据(数据库行)的状态,事物id等。

    由于数据存储需要对齐(8的整数倍,整体对外长度为24字节),空行的长度为24字节。另外还有4字节的指针。即一条空行总共占用24+4=28字节。

           

    1.7.  heap_page_items函数

    显示堆页面上的所有行指针。param1get_raw_page函数的返回值

           lp:

           lp_off: tuple在页面中的位置

           lp_len:tuple的实际长度(tuple header + data,最终长度需要取整为8B的整数倍)

           t_xmint_xmax: 插入,删除和更新时的事物id,插入时xmin写入当前事物id,删除时xmax写入事物id。更新也是先删除再插入

           t_field3:

           t_ctid:物理id,用于寻址数据在该页的位置(或者用于指向下一页索引)

    1.8.  实战1-单条数据占用内存

    l  sql语句

           drop table if EXISTS test1;

    create table test1(id int);

    --vacuum analyze test1;

    insert into test1 values(1);

    select * from page_header(get_raw_page('test1', 'main', 0));

    insert into test1 values(2);

    select * from page_header(get_raw_page('test1', 'main', 0));

    insert into test1 values(300);

    select * from page_header(get_raw_page('test1', 'main', 0));

    select * from heap_page_items(get_raw_page('test1',0));

    l  分析

           通过下图可以看出,每插入一条int数据,lower增加4字节(item id是从页头开始写的,写在header的后面),upper减少32字节(tuple是从页尾开始写的,tuple header + data = 24 + 4 = 28,因为要取8的整数倍,所以为32字节)。

    t_data存放的是数据的内容,注意下面标红的2c010000(实际是0X012c)对应值为300.

    l  额外结论

    根据上面的理论,目前来看,存储4字节的int8字节的int消耗磁盘大小是一样的。(该定论局限于本表只有一个字段的情况下)

    可以通过以下方式证明:

                  drop table if EXISTS test1;

    create table test1(id char(7));

    insert into test1 values('a');

    select * from page_header(get_raw_page('test1', 'main', 0));

    insert into test1 values('b');

    select * from page_header(get_raw_page('test1', 'main', 0));

    insert into test1 values('c');

    select * from page_header(get_raw_page('test1', 'main', 0));

    select * from heap_page_items(get_raw_page('test1',0));

    说明:char的长度可以手动指定,char中的长度7实际占用8字节。

    另外:

      null字段不占用tuple中的空间

      定长字段(int,char...)占用磁盘空间固定,和声明的一致

      变长字段(varchar, text...)占用的磁盘空间由实际数据而定,而不是声明的长度。

    1.9.  实战2-计算单页的存储量(226行)

    计算一页可以存储的单列int类型数据数量

    l  已知

           page页默认大小为8KB8192字节)

    page header 24字节

           每插入一行,生成一个item id4字节)和一个tupletuple header + data,共32字节)。

    l  理论值

           (8192-24/ 36 = 226

    (8192-24% 36 = 32

    所以理论上,一页可以存储226行只有一个int列的数据,属于空间大小为32B

    l  测试sql

           drop table if EXISTS test1;

    create table test1(id int);

    insert into test1 select generate_series(1,226);

    select * from page_header(get_raw_page('test1', 'main', 0));

    select * from heap_page_items(get_raw_page('test1',0));

    select count(*) from heap_page_items(get_raw_page('test1',0));

    insert into test1 values(300);

    l  分析

           插入226条数据后,通过page heaader查看upper-lower=32

           通过page items查看第一页存在226条数据。

           再插入一条,发现第一页还是226条数据,第二页有一条数据

           说明第一页已经插满。

     

    3.  存储结构

    l  存储方式共有4

    PLAIN :避免压缩和行外存储。

    EXTENDED :先压缩,后行外存储。

    EXTERNAL :允许行外存储,但不许压缩。

    MAIN :允许压缩,尽量不使用行外存储更贴切。

    l  何时压缩Tuple数据

           Tuple大小超过大概2KB时,PostgreSQL会尝试基于LZ压缩算法进行压缩。

    l  何时行外存储(TOAST

    行外存储toasted属性的本意是The Oversized-Attribute Storage Technique,对于某个超长的属性单独存储。当某行数据超过PostgreSQL页大小(8k)后,会将这个页放到系统命名空间pg_toast下的一个单独的表中,而在原表中存储一个TOAST pointer

    l  实战解读

    create table tab3(id int primary key,info text);

     备注:

      https://www.postgresql.org/docs/current/storage-page-layout.html     官方文档

  • 相关阅读:
    Go基础
    格式化输入输出
    常量
    Go语言基础之变量
    跨平台编译
    Hello World
    使用go module导入本地包
    Go语言之依赖管理
    Go包管理
    Go项目结构
  • 原文地址:https://www.cnblogs.com/gc65/p/11011885.html
Copyright © 2011-2022 走看看