PostgreSQL孤儿文件

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 与所有其他关系数据库系统一样,PostgreSQL需要通过写入wal日志或在Checkpoint时同步数据到数据文件来持久化数据到磁盘上。对于数据文件,一旦Relation达到SEGMENT_SIZE(默认1GB),PostgreSQL就会创建一个新的数据文件。因此如果Relation持续增长,则该Relation可能会由多个文件组成。在这篇文章中想要考虑的问题是,是否可能存在孤儿文件。

与所有其他关系数据库系统一样,PostgreSQL需要通过写入wal日志或在Checkpoint时同步数据到数据文件来持久化数据到磁盘上。对于数据文件,一旦Relation达到SEGMENT_SIZE(默认1GB),PostgreSQL就会创建一个新的数据文件。因此如果Relation持续增长,则该Relation可能会由多个文件组成。在这篇文章中想要考虑的问题是,是否可能存在孤儿文件。如果文件不是任何Relation的组成部分或引用,但该文件仍在磁盘上,则该文件将成为孤儿文件。一方面会浪费磁盘空间,另一方面,也会与PostgreSQL Catalog中存储的内容不一致。

先建一个空表:

postgres=# createtable t1 ( a int);CREATETABLE

表创建好以后会在磁盘上创建一个文件,可以通过查询PostgreSQL得到相关的文件信息:

postgres=# select pg_relation_filepath('t1'); pg_relation_filepath 
---------------------- base/12724/24577(1 row)

可以通过操作系统的命令查看文件信息:

postgres@db ls-la$PGDATA/base/12724/24577
-rw-------. 1 postgres postgres 0 Nov 1316:53 /u02/pgdata/14/base/12724/24577

现在表中还没有任何内容,所以数据文件是空的。PostgreSQL提供了一个叫oid2name的小工具,可用来定位指定Relation的位置。

postgres@db oid2name -t t1 -xFrom database "postgres":
  Filenode  Table Name    Oid  Schema  Tablespace
-------------------------------------------------24577          t1  24577  public  pg_default

一旦我们开始向Relation中插入数据,对应的数据文件就开始增长,如果其尺寸达到segment_size,PostgreSQL将为Relation添加一个新文件(这里要注意,我的segment_size 设置成了2GB,而不是缺省的1GB):

postgres=# insertinto t1 select*from generate_series(1,1000000);INSERT01000000postgres=# ! ls -lha $PGDATA/base/12724/24577-rw-------. 1 postgres postgres 35M Nov 13 17:03 /u02/pgdata/14/base/12724/24577postgres=# insertinto t1 select*from generate_series(1,100000000);INSERT0100000000postgres=# ! ls -la $PGDATA/base/12724/24577*-rw-------. 1 postgres postgres 2147483648 Nov 13 17:07 /u02/pgdata/14/base/12724/24577-rw-------. 1 postgres postgres 1513545728 Nov 13 17:08 /u02/pgdata/14/base/12724/24577.1-rw-------. 1 postgres postgres     917504 Nov 13 17:07 /u02/pgdata/14/base/12724/24577_fsm

*_fsm文件是自由空间映射(free space map),用于跟踪数据文件的可用空间。


现在已经清楚了磁盘上发生了什么,我们将回到本文的第一个问题:磁盘上的文件会不会不属于任何Relation?考虑这个例子:在一个会话中,我们启动了一个新事务并创建了一个空表,但没有提交该事务。同时我们先取得会话ID和数据文件在磁盘上的位置:

postgres=# begin;BEGINpostgres=# createtable t2 ( a int);CREATETABLEpostgres=# select pg_relation_filepath('t2'); pg_relation_filepath 
---------------------- base/12724/24580(1 row)postgres=# select*from pg_backend_pid(); pg_backend_pid 
----------------7170(1 row)

事务尚未提交,但我们已经可以在磁盘上看到相关文件了,PostgreSQL已经创建了它:

postgres=# ! ls -la $PGDATA/base/12724/24580-rw-------. 1 postgres postgres 0 Nov 13 17:17 /u02/pgdata/14/base/12724/24580

如果此时服务器挂了或者该会话OOM被杀掉了,会发生什么?我们可以用kill -9 PID来模拟杀掉该会话:

postgres@db kill -97170

返回刚才的psql会话,发现连接已丢失,但会立即重连:

postgres-# select1;server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: Succeeded.
postgres=# select1; ?column? ----------1(1 row)

总之,在通过事务创建表并且在事务被提交前终止会话,这时事务必须被回滚,表也不应该存在:

postgres=# select*from t2;ERROR:  relation "t2" does not exist
LINE 1:select*from t2;

这很好,也是我们所期待的。但我们还能看到磁盘上的文件吗?

postgres@db ls -lha $PGDATA/base/12724/24580-rw-------. 1 postgres postgres 0 Nov 13 17:17 /u02/pgdata/14/base/12724/24580

现在我们有了一个不属于PostgreSQL已知的任何Relation的孤儿文件:

postgres=# select relname from pg_class where oid ='24580'; relname 
---------(0 rows)

因此,可能会出现需要清理磁盘上的文件的情况。想象一下,当你向Relation中导入大量数据,就在导入即将完成前前,会话被终止了:

postgres=# begin;BEGINpostgres=# createtable t3 ( a int);CREATETABLEpostgres=# select pg_relation_filepath('t3'); pg_relation_filepath 
---------------------- base/12724/32769(1 row)postgres=# select*from pg_backend_pid(); pg_backend_pid 
----------------7577(1 row)postgres=# insertinto t3 select*from generate_series(1,10000000);server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.

现在文件不再为空,磁盘空间被占用:

postgres@db ls -lha $PGDATA/base/12724/32769-rw-------. 1 postgres postgres 235M Nov 13 17:42 /u02/pgdata/12/base/12724/32769

在最糟糕的情况下,这可能会浪费数GB或TB的空间。有方法可以检测这种孤儿文件吗?您需要将PostgreSQL记录在目录中的内容与文件系统进行比较,然后删除所有PostgreSQL不知道的内容,这需要非常非常小心地完成。

首先,需要获取要检查的数据库的OID:

postgres=# select oid from pg_database where datname ='postgres';  oid  
-------12724(1 row)

完成后,就知道了其在磁盘上的位置,即$PGDATA/base/[数据库OID](这里没考虑表空间)。从这里开始,你可以列出应该属于某个Relation的所有文件:

postgres=# select*from pg_ls_dir ('/u02/pgdata/14/base/12724')as file 
where file  ~'^[0-9]*'file  
-------1255124712491259...

所有这些都应该在pg_class中有对应的条目(否则PostgreSQL不知道它们)。

最后,获取孤儿文件的列表:

select*from pg_ls_dir ('/u02/pgdata/14/base/12724')as file 
where file  ~'^[0-9]*'and file::textnotin(select relfilenode::textfrom pg_class);file 
------- 163852458032769(3 rows)

这就是你需要仔细检查的文件。如果您确定它是一个孤儿文件,你可以将其删除(当然,删除前一定要先备份)。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
6月前
|
关系型数据库 Linux PostgreSQL
这个错误是因为Flink CDC在尝试访问PostgreSQL的"decoderbufs"文件时,发现该文件不存在
【1月更文挑战第23天】【1月更文挑战第111篇】这个错误是因为Flink CDC在尝试访问PostgreSQL的"decoderbufs"文件时,发现该文件不存在
174 11
|
关系型数据库 数据库 PostgreSQL
PostgreSQL 12: Recovery.conf 文件参数合并到 postgresql.conf
PostgreSQL 12 的一个重要变化是 recovery.conf 配置文件中的参数合并到 postgresql.conf,recovery.conf 不再使用,我们看看手册的说明,如下: 发行说明 Move recovery.
4810 0
|
监控 关系型数据库 数据库
PostgreSQL 恢复模式错误日志增强 - 提供正在恢复的WAL(XLOG)文件位置
标签 PostgreSQL , the database system is starting up , the database system is in recovery mode 背景 当数据库异常停库,再次启动时。
3017 0
|
关系型数据库 PostgreSQL
PostgreSQL如何删除不使用的xlog文件
PostgreSQL如何删除不使用的xlog文件
153 0
|
Oracle 安全 关系型数据库
如何在openGauss/PostgreSQL手动清理XLOG/WAL 文件?
openGauss/PostgreSQL中的预写式日志WAL(Write Ahead Log),又名Xlog或redo log,相当于oracle的online redo log, 不同的是oracle online redo log是提前创建几组滚动使用,但在opengauss中只需要本配置参数控制WAL日志的周期,数据库会一直的创建并自动清理,但存在一些情况WAL日志未清理导致目录空间耗尽,或目录空间紧张时手动删除wal日志时,比如如何确认在非归档模式下哪些WAL日志文件可以安全删除?
947 0
|
6月前
|
SQL 关系型数据库 MySQL
MySQL【实践 02】MySQL迁移到PostgreSQL数据库的语法调整说明及脚本分享(通过bat命令修改mapper文件内的SQL语法)
MySQL【实践 02】MySQL迁移到PostgreSQL数据库的语法调整说明及脚本分享(通过bat命令修改mapper文件内的SQL语法)
260 0
|
6月前
|
SQL 关系型数据库 Shell
postgresql|数据库|批量执行SQL脚本文件的shell脚本
postgresql|数据库|批量执行SQL脚本文件的shell脚本
325 0
|
存储 Oracle 关系型数据库
PostgreSQL技术大讲堂 - 第15讲:数据文件与块存储结构
PostgreSQL技术大讲堂 - 第15讲:数据文件与块存储结构
257 1
|
关系型数据库 数据库 PostgreSQL
PG从小白到专家 - Part 11:PostgreSQL控制文件作用与管理
PG从小白到专家 - Part 11:PostgreSQL控制文件作用与管理
270 1
|
SQL 关系型数据库 Shell
解决Windows下Postgresql使用copy导入out文件报Permission denied的问题
解决Windows下Postgresql使用copy导入out文件报Permission denied的问题
236 0
解决Windows下Postgresql使用copy导入out文件报Permission denied的问题

相关产品

  • 云原生数据库 PolarDB