
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 TABLEpostgres=# select oid,relname,relfilenode from pg_class where relname = 't2'; oid | relname | relfilenode-------+---------+------------- 16808 | t2 | 16811(1 row)postgres=# checkpoint;CHECKPOINTpostgres=# \qmovead@movead-PC:/h2/pgpgpg/bin$ ll ../data/base/12835/16808ls: 无法访问'../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/16811movead@movead-PC:/h2/pgpgpg/bin$postgres=# select oid, relname, relfilenode,reltablespacefrom pg_classwhere 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.mapmovead@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.mapmovead@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 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!