• 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)来标识。

  • 相关阅读:
    Tree
    a letter and a number
    A problem is easy
    connect设置超时的方法
    C++客户端访问Java服务端发布的SOAP模式的WebService接口
    gSoap的“error LNK2001: 无法解析的外部符号 _namespaces”解决方法
    先序序列和后序序列并不能唯一确定二叉树
    二叉树的非递归遍历
    web service,soap ,http,tcp,udp
    byte[]数组和int之间的转换
  • 原文地址:https://www.cnblogs.com/sandata/p/15000758.html
Copyright © 2020-2023  润新知