计算机
内数据访问的时间CPU L1->CPU L2->DRAM->SSD->HDD->Network Storage->Tape Archives
不同层次的访问,访问的时间差距很大。上图的左边是每个层次的硬件访问数据的时间周期,上图的右边是不同硬件访问时间的放大,越上层访问越短,越下层访问时间越长;但是从容量上看越上层的容量越小,越下层的容量越大。PG
磁盘数据到内存概览DRAM
来加速数据库磁盘数据的访问。比如PG
中的share_buffer
,全局为PG
数据库中表存储的数据page
提供缓冲空间。当用户执行查询语句的时候,首先会去查询share_buffer
中这个数据page
是否在缓存区中,如果在就返回page
;如果不在则去磁盘读取这个数据的page
到share_buffer
最后返回。share_buffer
,另外一个是page
.下面核心会聚焦到这2个点上,了解PG
是如何实现这些逻辑PG
中的数据对象
PG
中一般会有三种对象,分别是数据库
、表
、索引
.三者之间的关系如下
PG
中一个表一般会有三种类型的数据,一个是fsm
文件表示当前数据表中可用的空闲空间,另外一个是vm
文件来表示数据表中数据可见性的映射,最后一个是以oid
来表示的数据文件.fsm
是基于page来管理空闲空间,其采用binary-tree
的方式进行管理。vm
中的可见性也是基于page
来管理。// 创建测试表
perryn_demo=> create table email(id int,name varchar(255));
CREATE TABLE
// 查询的表的OID
perryn_demo=> select oid,relfilenode from pg_class where relname='email';
oid | relfilenode
-------+-------------
16386 | 16386
(1 row)
// 插入数据
perryn_demo=> insert into email SELECT generate_series(1,200000),repeat(chr(int4(random()*26)+65),200);
INSERT 0 190001
PG
中的Page
PG
中的Page
中都有一个PageHeader
,其次是多个数据指针。数据的Page
是从尾部Special
开始写。每个Tuple
也包含了Tuple Header
和Tuple Data
.
Page
在PG
使用了PageHeaderData
来表示每个Page
的头。这里存储了每个Page
的meta信息,PageHeaderData->pd_linp
是一个数组质指向Page
内的Tuple
typedef struct PageHeaderData
{
// 上一次做更改的xlog的lsn号
PageXLogRecPtr pd_lsn;
// 如果设置了page checksum这里就存储了checksun
uint16 pd_checksum;
// flag的设置
uint16 pd_flags;
// 执行free space的偏移量
LocationIndex pd_lower;
// 执行free space的结束位置的偏移量
LocationIndex pd_upper;
// 执行special space的偏移量
LocationIndex pd_special;
// page的版本号
uint16 pd_pagesize_version;
// 最旧的xid
TransactionId pd_prune_xid;
// page header的指针数组
ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER];
} PageHeaderData;
typedef PageHeaderData *PageHeader;
typedef struct ItemIdData
{
// 物理page的偏移量
unsigned lp_off:15,
// line poiner的状态
lp_flags:2,
// tuple的长度
lp_len:15;
} ItemIdData;
typedef ItemIdData *ItemId;
Tuple
都有一个HeapTupleHeaderData
作为Tuple
的header.HeapTupleHeaderData
并没有存储任何的行的属性信息,属性信息存储在TupleDescData
// 包含在tuple header中的信息
typedef struct HeapTupleFields
{
// 插入事务ID
TransactionId t_xmin;
// 删除事务ID
TransactionId t_xmax;
union
{
// 插入或者删除的cmd id
CommandId t_cid;
TransactionId t_xvac; /* old-style VACUUM FULL xact ID */
} t_field3;
} HeapTupleFields;
// 记录tuple的在位置信息
typedef struct ItemPointerData
{
BlockIdData ip_blkid;
OffsetNumber ip_posid;
}
typedef struct HeapTupleHeaderData HeapTupleHeaderData;
struct HeapTupleHeaderData
{
// 每个元组的事务信息/记录的多少列信息
union
{
// tuple事务信息存储在t_heap中
HeapTupleFields t_heap;
DatumTupleFields t_datum;
} t_choice;
// 这个tuple的行记录所在的位置信息
ItemPointerData t_ctid; /* current TID of this or newer tuple (or a
* speculative insertion token) */
// t_infomask2和t_infomask 决定
#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2 2
uint16 t_infomask2;
#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK 3
uint16 t_infomask;
// t_hoff 表示行数据所在的位置
#define FIELDNO_HEAPTUPLEHEADERDATA_HOFF 4
uint8 t_hoff;
/* ^ - 23 bytes - ^ */
#define FIELDNO_HEAPTUPLEHEADERDATA_BITS 5
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */
/* MORE DATA FOLLOWS AT END OF STRUCT */
};
Tuple
的属性信息存储在TupleDescData
.typedef struct TupleDescData
{
int natts; /* number of attributes in the tuple */
Oid tdtypeid; /* composite type ID for tuple type */
int32 tdtypmod; /* typmod for tuple type */
int tdrefcount; /* reference count, or -1 if not counting */
TupleConstr *constr; /* constraints, or NULL if none */
/* attrs[N] is the description of Attribute Number N+1 */
FormData_pg_attribute attrs[FLEXIBLE_ARRAY_MEMBER];
} TupleDescData;
typedef struct TupleDescData *TupleDesc;