一、关于pg_filenode.map
通常情况下,PostgreSQL中每张表在磁盘上都有与之相关的文件,而这些文件的名字便是relfilenode,我们可以通过pg_class的relfilenode字段去查询。
postgres=# select relname,oid,relfilenode,reltablespace from pg_class where relname in ('pg_database','pg_class','pg_type','pg_namespace','pg_attribute','tab_1');
relname | oid | relfilenode | reltablespace
--------------+-------+-------------+---------------
pg_type | 1247 | 0 | 0
tab_1 | 33125 | 33136 | 0
pg_namespace | 2615 | 2615 | 0
pg_database | 1262 | 0 | 1664
pg_attribute | 1249 | 0 | 0
pg_class | 1259 | 0 | 0
(6 rows)
对于一张普通表,其relfilenode和oid默认是一样的。系统表有的也是。但当我们对该表进行了例如vacuum full、truncate之类的操作,表重建后,那么relfilenode便会发生变化。
pg_class视图里,通过reltablespace字段我们也可以发现分为两类系统表:一类是pg_type、pg_attribute、pg_proc和pg_class,它们是非共享的表,在内核中我们称为Nail表。而另一类则是reltablespace为1664的,即在pg_global表空间里的共享表。
有一部分特殊的表我们会发现其对应的表relfilenode为0,官方文档的解释为:0表示这是一个“映射”关系,其磁盘文件名取决于底层状态。对于这种访问十分频繁的系统表,不希望每次都是从一些其它的系统表去查询,这样性能便会非常低,它们便是通过pg_filenode.map文件去进行管理的。pg_filenode.map在base的目录每个库的目录以及global目录下均有一个。
postgres@ubuntu-linux-22-04-desktop:~/data-16$ ll global/pg_filenode.map
-rw------- 1 postgres postgres 524 Dec 26 01:06 global/pg_filenode.map
postgres@ubuntu-linux-22-04-desktop:~/data-16$ ll base/*/pg_filenode.map
-rw------- 1 postgres postgres 524 Dec 26 01:06 base/1/pg_filenode.map
-rw------- 1 postgres postgres 524 Jan 17 10:40 base/13008/pg_filenode.map
-rw------- 1 postgres postgres 524 Dec 26 01:06 base/16385/pg_filenode.map
-rw------- 1 postgres postgres 524 Dec 26 01:06 base/4/pg_filenode.map
在global和base对应数据库的pg_filenode.map文件中,将这些系统表的oid与relfileno做映射,文件的大小为512,刚好是一个OS disk sector的大小。这个文件最多存放62条系统catalog表的记录
二、base目录对应数据库目录下的pg_filenode.map(非共享)
postgres@ubuntu-linux-22-04-desktop:~/data-16/base/13008$ pg_filedump -m pg_filenode.map
*******************************************************************
* PostgreSQL File/Block Formatted Dump Utility
*
* File: pg_filenode.map
* Options used: -m
*******************************************************************
Magic Number: 0x592717 (CORRECT)
Num Mappings: 17
Detailed Mappings list:
OID: 1259 Filenode: 41317
OID: 1249 Filenode: 1249
OID: 1255 Filenode: 1255
OID: 1247 Filenode: 1247
OID: 2836 Filenode: 2836
OID: 2837 Filenode: 2837
OID: 4171 Filenode: 4171
OID: 4172 Filenode: 4172
OID: 2690 Filenode: 2690
OID: 2691 Filenode: 2691
OID: 2703 Filenode: 2703
OID: 2704 Filenode: 2704
OID: 2658 Filenode: 2658
OID: 2659 Filenode: 2659
OID: 2662 Filenode: 41320
OID: 2663 Filenode: 41321
OID: 3455 Filenode: 41322
可以结合脚本过滤,原本数据库里系统表和oid的对应关系如下,其中pg_toast_1255和pg_toast_1247分别为pg_proc和pg_type的toast表
//拼接所有的oid,并加上相关字段,便于后边查询对象。
postgres@ubuntu-linux-22-04-desktop:~/data-16/base/13008$ pg_filedump -m pg_filenode.map | grep OID| awk '{print "or oid="$2}'|awk 'ORS=NR%17?" ":"\n"{print}'
or oid=1259 or oid=1249 or oid=1255 or oid=1247 or oid=2836 or oid=2837 or oid=4171 or oid=4172 or oid=2690 or oid=2691 or oid=2703 or oid=2704 or oid=2658 or oid=2659 or oid=2662 or oid=2663 or oid=3455
postgres=# select relname,oid,relfilenode,reltablespace from pg_class where oid=1259 or oid=1249 or oid=1255 or oid=1247 or oid=2836 or oid=2837 or oid=4171 or oid=4172 or oid=2690 or oid=2691 or oid=2703 or oid=2704 or oid=2658 or oid=2659 or oid=2662 or oid=2663 or oid=3455;
relname | oid | relfilenode | reltablespace
-----------------------------------+------+-------------+---------------
pg_type | 1247 | 0 | 0
pg_toast_1255 | 2836 | 0 | 0
pg_toast_1247 | 4171 | 0 | 0
pg_toast_1255_index | 2837 | 0 | 0
pg_toast_1247_index | 4172 | 0 | 0
pg_proc_oid_index | 2690 | 0 | 0
pg_proc_proname_args_nsp_index | 2691 | 0 | 0
pg_type_oid_index | 2703 | 0 | 0
pg_type_typname_nsp_index | 2704 | 0 | 0
pg_attribute_relid_attnam_index | 2658 | 0 | 0
pg_attribute_relid_attnum_index | 2659 | 0 | 0
pg_class_oid_index | 2662 | 0 | 0
pg_class_relname_nsp_index