zoukankan      html  css  js  c++  java
  • 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=# 
    

      

  • 相关阅读:
    android 布局 使用 viewPager 时,如何解决 和 子页面 长按滑动 冲突问题
    C++ 与 php 的交互 之----- C++ 异步获取 网页文字内容,异步获取 php 的 echo 值。
    站在巨人的肩膀上---重新自定义 android- ExpandableListView 收缩类,实现列表的可收缩扩展
    C/C++ char a[ ] 和 char *a 的差别,改变 char *a爆内存错误的原因
    android 真机调试出现错误 INSTALL_FAILED_INSUFFICIENT_STORAGE 的解决方法。
    android 如何获取手机的图片、视频、音乐
    《C程序设计语言》练习1-5
    《C 程序设计语言》练习1-4
    《C 程序设计语言》练习1-3
    关于 Cantor 集不可数的新观点
  • 原文地址:https://www.cnblogs.com/abclife/p/13948101.html
Copyright © 2011-2022 走看看