乐趣区

关于数据库:PostgreSQL-对象管理

概述

PostgreSQL 中的所有数据都存储在对应的文件中,即咱们常见到的文件。这些用来存储数据的文件独特形成了 PostgreSQL 整个数据库集簇,而数据库集簇是对 PostgreSQL 中多个数据库组成的汇合的称说。而在逻辑上,PostgreSQL 所有的数据库都是隶属于某个表空间,并且单个数据库不能跨表空间,而一个表空间中能够寄存多个数据库。表空间和数据库的关系属于多对多的关系。那么数据库中的数据是如何寄存在数据文件中的呢?接下来一起探索。

了解 oid 和 relfilenode 的关系

在 PostgreSQL 中,oid 全称为 Object identifier,称为对象标识符, 在 PostgreSQL 中,用于为每个对象调配的一个外部主键数据类型,其别名为 regclass,并且 oid 能够转换为整数。而 relfilenode 则为 PostgreSQL 数据库中对对象的物理访问信息。relfilenode 关联三个对应的 oid,即表空间的 oid,数据库的 oid 和对象的 oid。默认,在创立一个对象时,会为该对象应用 oid 映射到 relfilenode 编号。外部采纳 RelMapping 的形式进行映射,因而,在 PostgreSQL 中,所有对象的治理通过 oid 来治理外部对象,内部文件却通过 relfilenode 来治理。


postgres=# CREATE TABLE tab_test(id int,name varchar);
CREATE TABLE
postgres=# INSERT INTO tab_test VALUES(1,'PostgreSQL');
INSERT 0 1
postgres=# SELECT relname,oid,relfilenode FROM pg_class WHERE relname = 'tab_test';
 relname  |  oid  | relfilenode 
----------+-------+-------------
 tab_test | 16384 |       16384
(1 row)

通过下面的示例能够察看到创立的新的对象 oid 和 relfilenode 是一样的。其中默认的第一个 oid 为 16384


#define FirstNormalObjectId             16384

那么问题来了,如果在一个并发的多事务环境中,创立的对象会不会有抵触。

-- 事务 1
postgres=# BEGIN;
BEGIN
postgres=*# CREATE TABLE tab_test(id int,name varchar);
CREATE TABLE
postgres=*# SELECT relname,oid,relfilenode FROM pg_class WHERE relname = 'tab_test'; relname  |  oid  | relfilenode 
----------+-------+-------------
 tab_test | 16384 |       16384
(1 row)

-- 事务 2
postgres=# BEGIN;
BEGIN
postgres=*# CREATE TABLE tab_t(id int,name varchar);
CREATE TABLE
postgres=*# SELECT relname,oid,relfilenode FROM pg_class WHERE relname = 'tab_t';
 relname |  oid  | relfilenode 
---------+-------+-------------
 tab_t   | 16390 |       16390

实际上并不会,新的对象会为其调配一个新的的 oid。事务如果产生回滚,oid 不会被复用,oid 值递增。

relfilenode 值在以下状况中将会被重置,此刻 relfilenode 和 oid 将会不统一

1、VACUUM FULL

 postgres=# SELECT relname,oid,relfilenode
    FROM pg_class
    WHERE relname ~ 'tab_test';
     relname  |  oid  | relfilenode 
    ----------+-------+-------------
     tab_test | 16384 |       16384
    (1 row)

    postgres=# VACUUM tab_test;
    VACUUM
    postgres=# SELECT relname,oid,relfilenode
    FROM pg_class
    WHERE relname ~ 'tab_test';
     relname  |  oid  | relfilenode 
    ----------+-------+-------------
     tab_test | 16384 |       16384
    (1 row)
    postgres=# VACUUM FULL tab_test;
    VACUUM
    postgres=# SELECT relname,oid,relfilenode
    FROM pg_class
    WHERE relname ~ 'tab_test';
     relname  |  oid  | relfilenode 
    ----------+-------+-------------
     tab_test | 16384 |       16390

VACUUM FULL 操作对表和索引都会重置 relfilenode

2、REINDEX INDEX


postgres=# CREATE INDEX idx_tab_test_id ON tab_test USING btree(id);
CREATE INDEX
postgres=# SELECT relname,oid,relfilenode
FROM pg_class
WHERE relname ~ 'idx_tab_test_id';
     relname     |  oid  | relfilenode 
-----------------+-------+-------------
 idx_tab_test_id | 16401 |       16401
(1 row)

postgres=# REINDEX INDEX idx_tab_test_id ;
REINDEX
postgres=# SELECT relname,oid,relfilenode
FROM pg_class
WHERE relname ~ 'idx_tab_test_id';
     relname     |  oid  | relfilenode 
-----------------+-------+-------------
 idx_tab_test_id | 16401 |       16402
(1 row)

仅仅针对索引重置 relfilenode

3、CLUSTER table_name USING index_name


postgres=# SELECT relname,oid,relfilenode
FROM pg_class
WHERE relname ~ 'tab_test|idx_tab_test_id';
     relname     |  oid  | relfilenode 
-----------------+-------+-------------
 tab_test        | 16384 |       16390
 idx_tab_test_id | 16401 |       16402
(2 rows)
postgres=# CLUSTER tab_test USING idx_tab_test_id;
CLUSTER
postgres=# SELECT relname,oid,relfilenode
FROM pg_class
WHERE relname ~ 'tab_test|idx_tab_test_id';
     relname     |  oid  | relfilenode 
-----------------+-------+-------------
 tab_test        | 16384 |       16403
 idx_tab_test_id | 16401 |       16409
(2 rows)

CLUSTER 操作会对表和索引都重置 relfilenode

relfilenode 波及的函数

pg_relation_filonode()


postgres=# SELECT pg_relation_filenode('tab_test');
 pg_relation_filenode 
----------------------
                16410
(1 row)

pg_relation_filepath()


postgres=# SELECT pg_relation_filepath('tab_test');
 pg_relation_filepath 
----------------------
 base/13580/16410
(1 row)

结语

在 PostgreSQL 中,除了通过应用 oid 来作为对象标识符以外,另外一种标识类型为 xid,或者叫做事务 (简称为 xact) 标识符,在 relation 对象中,对应为暗藏列 xmin 和 xmax。当然 cid 用来作命令标识符,在 relation 对象中,以暗藏列 cmin 和 cmax 存在。元组标识符 tid 用于标识元组 (即行) 在表中的物理地位,在 relation 对象中应用 ctid,也属于暗藏属性,应用 k &v 模式查找对象,ctid 是一对 (blkno,blkindex) 来标识。

退出移动版