Mysql孤儿文件_PostgreSQL中的孤儿文件(orphaned data files)

创建一个测试表

postgres=# create table t1(a int);

CREATE TABLE

postgres=# select pg_relation_filepath('t1');

pg_relation_filepath

----------------------

base/75062/75297

(1 row)

postgres=#

在操作系统上已经可以看到该文件。

$ ls -la $PGDATA/base/75062/75297

-rw------- 1 postgres postgres 0 Nov 9 11:11 /data/pgdata/11/data/base/75062/75297

插入一些数据:

postgres=# show segment_size;

segment_size

--------------

1GB

(1 row)

postgres=# insert into t1 select * from generate_series(1,100000000);

INSERT 0 100000000

postgres=#

因为segment_size的设置为1GB,磁盘上已经有了多个文件

$ ls -la $PGDATA/base/75062/75297*

-rw------- 1 postgres postgres 1073741824 Nov 9 11:19 /data/pgdata/11/data/base/75062/75297

-rw------- 1 postgres postgres 1073741824 Nov 9 11:17 /data/pgdata/11/data/base/75062/75297.1

-rw------- 1 postgres postgres 1073741824 Nov 9 11:18 /data/pgdata/11/data/base/75062/75297.2

-rw------- 1 postgres postgres 439803904 Nov 9 11:19 /data/pgdata/11/data/base/75062/75297.3

-rw------- 1 postgres postgres 917504 Nov 9 11:18 /data/pgdata/11/data/base/75062/75297_fsm

现在,开启另一个会话(session 2)。

在session2中,启动一个事务并创建一个空表,但是不提交事务:

postgres=# begin;

BEGIN

postgres=# create table t2(a int);

CREATE TABLE

postgres=# select pg_relation_filepath('t2');

pg_relation_filepath

----------------------

base/75062/75300

(1 row)

postgres=# select * from pg_backend_pid();

pg_backend_pid

----------------

17710

(1 row)

postgres=#

在操作系统已经可以看到对应的文件:

$ ls -la $PGDATA/base/75062/75300

-rw------- 1 postgres postgres 0 Nov 9 11:23 /data/pgdata/11/data/base/75062/75300

如果这个时候,posrgresql server发生了奔溃、或者发生了oom被kill了或者session被kill了。会发生什么呢?

我们来模拟一下session被kill的场景:

$ kill -9 17710

再次在session2中执行查询:

postgres=# select 1;

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=#

这个session在事务提交之前被kill了,事务无法正常完成,但是事务已经创建了一个表。应该发生什么呢?事务被回滚,创建的表应该不存在了。

postgres=# select * from t2;

ERROR: relation "t2" does not exist

LINE 1: select * from t2;

^

postgres=#

这正是我们所预期的。但在操作系统上,文件仍然存在:

$ ls -la $PGDATA/base/75062/75300

-rw------- 1 postgres postgres 0 Nov 9 11:23 /data/pgdata/11/data/base/75062/75300

这样,文件就成了孤儿文件(orphaned file)。

postgresql并不知道这个文件属于哪个relation

postgres=# select relname from pg_class where oid = '75300';

relname

---------

(0 rows)

postgres=#

这样,你就需要自己手动清理孤儿文件了!

假设你做了大量的数据的加载,就在加载完成之前,会话被杀死:

postgres=# begin;

BEGIN

postgres=# create table t3(a int);

CREATE TABLE

postgres=# select pg_relation_filepath('t3');

pg_relation_filepath

----------------------

base/75062/99528

(1 row)

postgres=# select * from pg_backend_pid();

pg_backend_pid

----------------

21988

(1 row)

postgres=# insert into t3 select * from generate_series(1,1000000000);

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: Failed.

虽然会话被kill了。但是磁盘上的空间并没有被释放。

$ ls -la $PGDATA/base/75062/99528*

-rw------- 1 postgres postgres 1073741824 Nov 9 11:51 /data/pgdata/11/data/base/75062/99528

-rw------- 1 postgres postgres 413777920 Nov 9 11:51 /data/pgdata/11/data/base/75062/99528.1

-rw------- 1 postgres postgres 385024 Nov 9 11:51 /data/pgdata/11/data/base/75062/99528_fsm

在最糟糕的时候,可能会占用大量的磁盘空间。那是否有什么方法去检测这些孤儿文件呢?

你需要比较postgresql中的目录表中的记录和文件系统上信息,然后删除这些孤儿文件。这个过程需要小心谨慎。

首先获得你要检测的数据库的oid:

postgres=# select oid from pg_database where datname = 'postgres';

oid

-------

75062

(1 row)

postgres=#

这样就可以知道文件在文件系统上的位置。即 $PGDATA/base/[OID_OF_THE_DATABASE]

然后,获得孤儿文件:

postgres=# select * from pg_ls_dir ( '/data/pgdata/11/data/base/75062' ) as file where file ~ '^[0-9]*$' and file::text not in (select oid::text from pg_class );

file

-------

75280

75281

75282

75283

75300

83144

99528

(7 rows)

postgres=#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值