PostgreSQL目录结构之base目录

base目录

对于集簇里的每个数据库,在$PGDATA/base里都有一个子目录对应,子目录的名字为该数据库在 pg_database里的 OID。

#查看各个数据库的oid
testdb=# select oid, datname from pg_database;
  oid  |  datname  
-------+-----------
 13025 | postgres
 16384 | testdb
     1 | template1
 13024 | template0
(4 rows)

每一张表的数据(大部分)又是放在 $PGDATA/base/{dboid}/{relfilenode} 这个文件里面,relfilenode一般情况下和和tboid一致,但有些情况下也会变化,如TRUNCATEREINDEXCLUSTER以及某些形式的ALTER TABLE

#查询relowner
testdb=# select oid,rolname from pg_authid where rolname='postgres';
 oid | rolname  
-----+----------
  10 | postgres
(1 row)
#查询pg_class
testdb=# select relname,relowner,relfilenode from pg_class;
                    relname                    | relowner | relfilenode 
-----------------------------------------------+----------+-------------
 testtb                                        |       10 |       16385
 testtb_index                                  |       10 |       16388
 testtb2                                       |       10 |       16389
 ...

包含文件

$PGDATA/base/{dboid}中通常会包含三种文件:例如1638516385_fsm16385_vm,分别是该数据库对应表的数据或索引文件、其对应的空闲空间映射文件、其对应的可见性映射文件。

数据文件

在表或者索引超过1GB之后,它就被划分成1GB大小的段。 第一个段的文件名和文件节点相同,随后的段被命名为 filenode.1filenode.2等等。这样的安排避免了在某些有文件大小限制的平台上的问题。

#创建测试表
testdb=# create table testtb4(id int,name varchar(64));
CREATE TABLE
#查看表文件存储位置
testdb=# select pg_relation_filepath('testtb4');
 pg_relation_filepath 
----------------------
 base/16384/16403
(1 row)
#插入大量数据
testdb=# insert into testtb4 SELECT generate_series(1,20000000) as key, md5(random()::text);
INSERT 0 20000000
#查看目录文件
[root@ff1c61e75696 base]# ll 16384 |grep 16403
-rw------- 1 postgres postgres 1073741824 Oct 30 09:11 16403
-rw------- 1 postgres postgres  291594240 Oct 30 09:13 16403.1
-rw------- 1 postgres postgres     352256 Oct 30 09:09 16403_fsm
TOAST表

如果一个表的列中可能存储相当大的项,那么该表就会有个与之相关联的TOAST(The Oversized-Attribute Storage Technique)表,它用于存储无法保留在在表行中的域值的行外存储。如果表有TOAST表,该表的pg_class.reltoastrelid链接到它的TOAST表。

TOAST表的存储策略:
  • PLAIN:避免压缩和行外存储。只有那些不需要TOAST策略就能存放的数据类型允许选择(例如int类型),而对于text这类要求存储长度超过页大小的类型,是不允许采用此策略的
  • EXTENDED:允许压缩和行外存储。一般会先压缩,如果还是太大,就会行外存储
  • EXTERNA:允许行外存储,但不许压缩。类似字符串这种会对数据的一部分进行操作的字段,采用此策略可能获得更高的性能,因为不需要读取出整行数据再解压
  • MAIN:允许压缩,但不许行外存储。不过实际上,为了保证过大数据的存储,行外存储在其它方式(例如压缩)都无法满足需求的情况下,作为最后手段还是会被启动。因此理解为:尽量不使用行外存储更贴切
TOAST字段:
  • chunk_id:用来表示特定TOAST值的OID,可以理解为具有同样chunk_id值的所有行组成原表的TOAST字段的一行数据
  • chunk_seq:用来表示该行数据在整个数据中的位置
  • chunk_data:实际存储的数据。
#创建测试表
CREATE TABLE
#查看表详情
testdb=# \d+ testtb3
                                   Table "public.testtb3"
 Column  |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
---------+---------+-----------+----------+---------+----------+--------------+-------------
 id      | integer |           |          |         | plain    |              | 
 content | text    |           |          |         | extended |              | 
#查看toastoid
testdb=# select relname,relfilenode,reltoastrelid from pg_class where relname='testtb3';
 relname | relfilenode | reltoastrelid 
---------+-------------+---------------
 testtb3 |       16393 |         16396
(1 row)
#查看toast表详情,其中pg_toast.pg_toast_{relfilenode}就是该表名
testdb=# \d+ pg_toast.pg_toast_16393;
TOAST table "pg_toast.pg_toast_16393"
   Column   |  Type   | Storage 
------------+---------+---------
 chunk_id   | oid     | plain
 chunk_seq  | integer | plain
 chunk_data | bytea   | plain
#插入一条数据
testdb=# insert into testtb3 values(1, 'content');
INSERT 0 1
testdb=# select * from testtb3;
 id | content 
----+---------
  1 | content
(1 row)
#查询pg_toast.pg_toast_16393,发现是没有数据的
testdb=# select * from pg_toast.pg_toast_16393;
 chunk_id | chunk_seq | chunk_data 
----------+-----------+------------
(0 rows)
#再插入一条字段超长的数据
insert into testtb3 values(2, repeat(md5(random()::text),20000));
testdb=# select id,length(content) from testtb3;
 id | length 
----+--------
  1 |      7
  2 | 640000
(2 rows)
#再查询pg_toast.pg_toast_16393,发现已经有数据
testdb=# select chunk_id,chunk_seq,length(chunk_data) from pg_toast.pg_toast_16393;
 chunk_id | chunk_seq | length 
----------+-----------+--------
    16405 |         0 |   1996
    16405 |         1 |   1996
    16405 |         2 |   1996
    16405 |         3 |   1381
(4 rows)

可以发现在testtb3中数据长度为640000,但是在pg_toast.pg_toast_16393中所有行加起来1996*3+1381=7369远小于640000,是因为toast做了数据压缩,而且toast每行最大长度为1996。‬

FSM文件

每一个堆和索引关系(除了哈希索引)都有一个空闲空间映射(FSM)来保持对关系中可用空间的跟踪。它伴随着主关系数据被存储在一个独立的关系分支中,以关系的文件节点号加上一个_fsm后缀命名。例如,如果一个关系的文件节点是12345,那么FSM被存储在一个名为12345_fsm的文件中,该文件与主关系文件在同一个目录中。

空闲空间映射被组织成一棵FSM页面的树。底层FSM页面存储了在每一个堆(或索引)页面中可用的空闲空间,对于每一个这样的页面使用一个字节来表示。上层FSM页面则聚集来自于下层页面的信息。

在每一个FSM页面中是一个二叉树,存储在一个数组中,每一个节点一个字节。每个叶节点表示一个堆页面或者一个下层FSM页面。在每一个非叶节点中存储了它孩子节点中的最大值。因此叶节点中的最大值被存储在根中。

但是,在新建表时不会产生_fsm_vm文件,直到pg执行VACUUM操作时,或者是第一次要使用_fsm_vm文件时才会生成。

#查看表文件存储位置
testdb=# select pg_relation_filepath('testtb2');
 pg_relation_filepath 
----------------------
 base/16384/16389
(1 row)
#查看16389
[root@ff1c61e75696 16384]# tree|grep 16389
├── 16389
#手动执行vacuum
[root@ff1c61e75696 16384]# su postgres 
bash-4.2$ vacuumdb -t testtb testdb2
bash-4.2$ vacuumdb -t testtb2 testdb
vacuumdb: vacuuming database "testdb"
#再查看16389
[root@ff1c61e75696 16384]# tree|grep 16389
├── 16389
├── 16389_fsm
├── 16389_vm

pg提供了一个插件pg_freespacemap可供我们查询FSM,该插件提供了一种方法来检查空闲空间映射(FSM)。它提供了一个称为pg_freespace的函数,或者准确地说是两个重载的函数。这些函数显示空闲空间映射中为一个给定页面所记录的值,或者显示关系中所有页面的记录值。

默认情况下,使用仅限于超级用户和pg_stat_scan_tables 角色的成员。可以使用GRANT给其他人授予访问权限。

#安装插件
postgres=# create extension pg_freespacemap;
CREATE EXTENSION
#查看插件
testdb=# \dx
                       List of installed extensions
      Name       | Version |   Schema   |           Description            
-----------------+---------+------------+----------------------------------
 pg_freespacemap | 1.2     | public     | examine the free space map (FSM)
 plpgsql         | 1.0     | pg_catalog | PL/pgSQL procedural language
(2 rows)
#查看可用函数
testdb=# \dxS+ pg_freespacemap
 Objects in extension "pg_freespacemap"
           Object description           
----------------------------------------
 function pg_freespace(regclass)
 function pg_freespace(regclass,bigint)
(2 rows)
#查看表的FSM
testdb=# SELECT * FROM pg_freespace('testtb2');
 blkno | avail 
-------+-------
     0 |  8000
(1 row)

VM文件

每一个堆关系都有一个可见性映射(VM)用来跟踪哪些页面只包含已知对所有活动事务可见的元组,它也跟踪哪些页面只包含未被冻结的元组。

pg提供了一个插件pg_visibility可供我们查询VM,该插件提供了一种方式来检查一个表的可见性映射(VM)以及页级别的可见性信息。它还提供了函数来检查可见性映射的完整性以及强制重建可见性映射。

#安装插件
postgres=# create extension pg_visibility;
CREATE EXTENSION
#查看插件
testdb=# \dx
                                      List of installed extensions
      Name       | Version |   Schema   |                          Description                           
-----------------+---------+------------+----------------------------------------------------------------
 pg_freespacemap | 1.2     | public     | examine the free space map (FSM)
 pg_visibility   | 1.2     | public     | examine the visibility map (VM) and page-level visibility info
 plpgsql         | 1.0     | pg_catalog | PL/pgSQL procedural language
(3 rows)
#查看可用函数
testdb=# \dxS+ pg_visibility
     Objects in extension "pg_visibility"
              Object description               
-----------------------------------------------
 function pg_check_frozen(regclass)
 function pg_check_visible(regclass)
 function pg_truncate_visibility_map(regclass)
 function pg_visibility(regclass)
 function pg_visibility(regclass,bigint)
 function pg_visibility_map(regclass)
 function pg_visibility_map(regclass,bigint)
 function pg_visibility_map_summary(regclass)
(8 rows)
#查看表可见的block
testdb=# SELECT * FROM pg_visibility('testtb2');
 blkno | all_visible | all_frozen | pd_all_visible 
-------+-------------+------------+----------------
     0 | t           | f          | t
(1 row)

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
# Nacos2.2版本数据库适配插件 ## 一、插件概述 ### 1.1、简介 从2022年12月14日发布的Nacos2.2正式版本开始,Nacos提供了数据源扩展插件,以便让需要进行其他数据库适配的用户自己编写插件来保存数据。当前项目插件目前已简单适配Postgresql,并抽象了一套常见的兼容项的方言类,开发者可以基于该设计,实现自定义分页逻辑即可。 如需Nacos2.1支持,请移步个人之前创建这个仓库,该仓库目前支持PostgreSQL、Oracle、达梦,简单的操作基本可以实现。 wuchubuzai2018/nacos-multidatasource 当前项目基于Nacos2.2版本的扩展插件口进行开发。 ### 2.2、插件工程结构说明 nacos-datasource-plugin-ext工程主目录 ----nacos-datasource-plugin-ext-base工程设计为数据库插件操作的适配抽象。 ----nacos-all-datasource-plugin-ext工程计划可打包所有适配的数据库插件 ----nacos-postgresql-datasource-plugin-ext工程可打包适配Postgresql的数据库插件 ## 二、下载和使用 IDEA导入时导入nacos-datasource-plugin-ext这个目录作为根目录即可。 ### 2.1、插件引入 **方式一:源码方式** 使用postgresql作为依赖引入到Nacos主分支源码中,使用Maven提前将当前工程Install到Maven仓库,然后在Pom.xml中引入如下依赖: ```xml <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-postgresql-datasource-plugin-ext</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> ``` 或引入all模块。 **方式二:打包形式引入** 在Nacos2.2的发布包环境下,下载当前插件项目源码,打包为jar包,将该文件放到nacos主目录下的plugins文件夹中,默认会使用Nacos的loader.path机制指定该插件的路径,打包插件可选择nacos-postgresql-datasource-plugin-ext打包即可。postgresql模块的打包默认会包含postgresql的jdbc驱动类和base依赖。 ### 2.2、修改数据库配置文件 在application.properties文件中声明postgresql的配置信息: ```java spring.datasource.platform=postgresql db.url.0=jdbc:postgresql://127.0.0.1:5432/nacos?tcpKeepAlive=true&reWriteBatchedInserts=true&ApplicationName=nacos_java db.user=nacos db.password=nacos db.pool.config.driverClassName=org.postgresql.Driver ``` ### 2.3、导入Postgresql的数据库脚本文件 导入nacos-postgresql的脚本文件,脚本文件在nacos-postgresql-datasource-plugin-ext/src/main/resources/schema文件夹下面. 上面操作完成后,启动Nacos即可。 ## 三、其他数据库插件开发 可参考nacos-postgresql-datasource-plugin-ext工程,新创建Maven项目,实现AbstractDatabaseDialect类,重写相关的分页操作逻辑与方法,并创建相应的mapper实现,减少了适配的成本。 目前对于Oracle、达梦数据库,仍然需要修改Nacos2.2的主分支代码,因为要兼容默认的命名空间ID为空的查询情况,社区官网未处理。 最近有时间,将进行Nacos主分支源码上关于Nacos的Oracle的兼容性适配,目前可以用Nacos2.1的改造代码进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只努力的微服务

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值