zoukankan      html  css  js  c++  java
  • 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)来标识。

  • 相关阅读:
    LeetCode 123. Best Time to Buy and Sell Stock III (stock problem)
    精帖转载(关于stock problem)
    LeetCode 122. Best Time to Buy and Sell Stock II (stock problem)
    LeetCode 121. Best Time to Buy and Sell Stock (stock problem)
    LeetCode 120. Triangle
    基于docker 搭建Elasticsearch5.6.4 分布式集群
    从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
    Harbor实现容器镜像仓库的管理和运维
    docker中制作自己的JDK+tomcat镜像
    docker镜像制作---jdk7+tomcat7基础镜像
  • 原文地址:https://www.cnblogs.com/sandata/p/15000758.html
Copyright © 2011-2022 走看看