PostgreSQL中的孤儿文件(orphaned data files)
2020-11-18 08:28 abce 阅读(928) 评论(0) 编辑 收藏 举报创建一个测试表
1 2 3 4 5 6 7 8 9 | postgres=# create table t1(a int ); CREATE TABLE postgres=# select pg_relation_filepath( 't1' ); pg_relation_filepath ---------------------- base/75062/75297 (1 row) postgres=# |
在操作系统上已经可以看到该文件。
1 2 | $ ls -la $PGDATA/base/75062/75297 -rw ------- 1 postgres postgres 0 Nov 9 11:11 /data/pgdata/11/data/base/75062/75297 |
插入一些数据:
1 2 3 4 5 6 7 8 | 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,磁盘上已经有了多个文件
1 2 3 4 5 6 | $ 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中,启动一个事务并创建一个空表,但是不提交事务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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=# |
在操作系统已经可以看到对应的文件:
1 2 | $ 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的场景:
1 | $ kill -9 17710 |
再次在session2中执行查询:
1 2 3 4 5 6 | 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了,事务无法正常完成,但是事务已经创建了一个表。应该发生什么呢?事务被回滚,创建的表应该不存在了。
1 2 3 4 5 | postgres=# select * from t2; ERROR: relation "t2" does not exist LINE 1: select * from t2; ^ postgres=# |
这正是我们所预期的。但在操作系统上,文件仍然存在:
1 2 | $ 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
1 2 3 4 5 6 | postgres=# select relname from pg_class where oid = '75300' ; relname --------- (0 rows ) postgres=# |
这样,你就需要自己手动清理孤儿文件了!
假设你做了大量的数据的加载,就在加载完成之前,会话被杀死:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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了。但是磁盘上的空间并没有被释放。
1 2 3 4 | $ 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:
1 2 3 4 5 6 7 | postgres=# select oid from pg_database where datname = 'postgres' ; oid ------- 75062 (1 row) postgres=# |
这样就可以知道文件在文件系统上的位置。即 $PGDATA/base/[OID_OF_THE_DATABASE]
然后,获得孤儿文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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=# |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2015-11-18 打开u盘时提示是否要将其格式化的提示