PG中的表由一个relfilenode值,即磁盘上表的文件名(除了外表和分区表)。通常情况下可以在Pg_class表找到这个值,然而也会查考一些表的relfilenode为0.本文介绍这些表relfilenode的内部处理流程。
PG中创建一个表后,会在系统被pg_class存储它的relfilenode值。下面例子,表创建后,OID和relfilenode都时16808。还可以在磁盘上看到16808文件。
postgres=# create table t2(i int);
CREATE TABLE
postgres=# select oid,relname,relfilenode frompg_class where relname = 't2';
oid | relname | relfilenode
-------+---------+-------------
16808 |t2 | 16808
(1 row)
postgres=# \q
movead@movead-PC:/h2/pgpgpg/bin$ ll../data/base/12835/16808
-rw-------+ 1 movead movead 0 12月 31 17:11../data/base/12835/16808
movead@movead-PC:/h2/pgpgpg/bin$
执行truncate、vacuum full等操作后,表数据被重写,并且表文件的relfilenode也会改变。下面测试显示了truncate后,t2的relfilenode值由16808变成16811.
postgres=# truncate t2;
TRUNCATE TABLE
postgres=# select oid,relname,relfilenode from pg_class where relname = 't2';
oid | relname | relfilenode
-------+---------+-------------
16808 | t2 | 16811
(1 row)
postgres=# checkpoint;
CHECKPOINT
postgres=# \q
movead@movead-PC:/h2/pgpgpg/bin$ ll ../data/base/12835/16808
ls: 无法访问'../data/base/12835/16808': 没有那个文件或目录
movead@movead-PC:/h2/pgpgpg/bin$ ll ../data/base/12835/16811
-rw-------+ 1 movead movead 0 12月 31 17:16 ../data/base/12835/16811
movead@movead-PC:/h2/pgpgpg/bin$
postgres=# select oid, relname, relfilenode,reltablespace
from pg_class
where relfilenode = 0 and relkind = 'r'
order by reltablespace;
oid | relname | relfilenode | reltablespace
------+-----------------------+-------------+---------------
1247 | pg_type | 0 | 0
1255 | pg_proc | 0 | 0
1249 | pg_attribute | 0 | 0
1259 | pg_class | 0 | 0
3592 | pg_shseclabel | 0 | 1664
1262 | pg_database | 0 | 1664
2964 | pg_db_role_setting | 0 | 1664
1213 | pg_tablespace | 0 | 1664
1261 | pg_auth_members | 0 | 1664
1214 | pg_shdepend | 0 | 1664
2396 | pg_shdescription | 0 | 1664
1260 | pg_authid | 0 | 1664
6000 | pg_replication_origin | 0 | 1664
6100 | pg_subscription | 0 | 1664
(14 rows)
postgres=#
上面的例子的查询可看到这些表的relfilenode都是0.pg_type、pg_proc、pg_attribute和pg_class是non-shared表,称为Nail表。剩余的表是pg_global表空间的shared表。
Pg_class表中的relfilenode字段告诉我们磁盘上存储的文件名是什么。例如在表t2上进行查询时,首先需要从pg_class中获取relfilenode,然后在磁盘上找到对于文件,接着才能进行打开和扫描。如果想查询磁盘上pg_class的文件名,那去哪里找relfilenode呢?有一系列函数提供了转换oid\relfilenode的函数。
postgres=# select pg_relation_filenode(1259);
pg_relation_filenode
----------------------
16475
(1 row)
postgres=# select pg_filenode_relation(0,16475);
pg_filenode_relation
----------------------
pg_class
(1 row)
postgres=# select pg_filenode_relation(0,16475)::oid;
pg_filenode_relation
----------------------
1259
(1 row)
postgres=#
通过调用pg_relation_filenode(),oid可以转换成relfilenode;通过pg_filenode_relation()函数可以将relfilenode转换成oid。
Shared和nail表的oid和relfilenode之间的关系没有存储在pg_class表,PG如何存储这个映射关系呢?
经过研究后,找到要给pg_filenode.map文件:
movead@movead-PC:/h2/pgpgpg/data/base/12835$ ll pg_filenode.map
-rw-------+ 1 movead movead 512 12月 31 15:10 pg_filenode.map
movead@movead-PC:/h2/pgpgpg/data/base/12835$
movead@movead-PC:/h2/pgpgpg/data/global$ ll pg_filenode.map
-rw-------+ 1 movead movead 512 12月 31 15:10 pg_filenode.map
movead@movead-PC:/h2/pgpgpg/data/global$
shared表的oid和relfilenode映射关系存储在global目录的pg_filenode.map中。Database为12835的nail表映射关系存储在12835目录的pg_filenode.map中。该文件存储的内容结构是:
typedef struct RelMapping
{
Oid mapoid; /* OID of a catalog */
Oid mapfilenode; /* its filenode number */
} RelMapping;
typedef struct RelMapFile
{
int32 magic; /* always RELMAPPER_FILEMAGIC */
int32 num_mappings; /* number of valid RelMapping entries */
RelMapping mappings[MAX_MAPPINGS];
pg_crc32c crc; /* CRC of all above */
int32 pad; /* to make the struct size be 512 exactly */
} RelMapFile;
本文主要介绍了PG的oid和relfilenode的两种表现方式,pg_relation_filenode()获取的值永远是正确的,但是从系统表中查询出的就可能是错误的。
https://www.highgo.ca/2021/01/12/the-mapping-of-oid-and-relfilenode-in-pg/
本文分享自 yanzongshuaiDBA 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!