• PostgreSQL的大对象以及空间使用 (2)


    在上一篇文章中,展示了插入大对象后,pg_largeobject表中有多少大对象使用空间。

    让我们再深入研究一下:

    该表有2个大对象(总共1024个记录):

    lob_test=# select pg_relation_size('pg_largeobject');
    pg_relation_size
    ------------------
              1441792
    (1 row)
    

    再来添加一个随机填充的文件:

    lob_test=# lo_import '/tmp/randoms';
    lo_import 16493
    lob_test=# select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              2842624
    (1 row)
    
    lob_test=# select oid, * from  pg_largeobject_metadata;
      oid  | lomowner | lomacl
    -------+----------+--------
     16491 |       10 |
     16492 |       10 |
     16493 |       10 |
    (3 rows)
    

    不出所料,因为不能压缩随机字符序列,所以大小又增加了171个块(有关解释,请参阅我的上一篇文章)

    如果您阅读了Frits Hoogland(https://fritshoogland.wordpress.com/category/postgresql/)撰写的一系列不错的博客文章,则应该了解pageinspect扩展名和t_infomask 16位掩码。

    让我们安装它并检查pg_largeobjects页面的内容:

    lob_test=# select * from page_header(get_raw_page('pg_largeobject',0));
         lsn     | checksum | flags | lower | upper | special | pagesize | version | prune_xid
    -------------+----------+-------+-------+-------+---------+----------+---------+-----------
     18/38004C10 |        0 |     0 |   452 |   488 |    8192 |     8192 |       4 |         0
    (1 row)
    
    -- same result (lower 452, upper 488) for blocks 1...3
    
    lob_test=# select * from page_header(get_raw_page('pg_largeobject',4));
         lsn     | checksum | flags | lower | upper | special | pagesize | version | prune_xid
    -------------+----------+-------+-------+-------+---------+----------+---------+-----------
     18/380179F8 |        0 |     0 |   360 |  2144 |    8192 |     8192 |       4 |         0
    (1 row)
    
    
    lob_test=# select * from page_header(get_raw_page('pg_largeobject',5));
         lsn     | checksum | flags | lower | upper | special | pagesize | version | prune_xid
    -------------+----------+-------+-------+-------+---------+----------+---------+-----------
     18/381386E0 |        0 |     0 |    36 |  1928 |    8192 |     8192 |       4 |         0
    (1 row)-- same result for the remaining blocks
    

    已经知道的一些数字,但是我们更宁愿将所有部分放在一起分析。我们知道:page header占用24个字节,并且行指针为每个元组使用4个字节。

    前4个页的偏移量较低,为452个字节,这意味着我们有(452-24)/ 4 = 107个元组。

    第5页(page number是4)的lower为360:(360-24)/ 4 = 84元组。

    其余页面的lower为36:(36-24)/ 4 = 3个元组。

    让我们检查是否正确:

    lob_test=# select generate_series as page,
     (select count(*) from heap_page_items(get_raw_page('pg_largeobject',generate_series)))  as tuples
     from generate_series(0,5);
     page | tuples
    ------+--------
        0 |    107
        1 |    107
        2 |    107
        3 |    107
        4 |     84
        5 |      3
    (6 rows)
    

    现在,让我们删除那1Mb的文件,并再次检查空间:

    lob_test=# lo_unlink 16492
    lo_unlink 16492
     
     
    lob_test=# select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              2842624
    (1 row)
     
    lob_test=# select oid, * from  pg_largeobject_metadata;
      oid  | lomowner | lomacl
    -------+----------+--------
     16491 |       10 |
     16493 |       10 |
    (2 rows)
     
    lob_test=# select generate_series as pageno, (select count(*) from heap_page_items(get_raw_page('pg_largeobject',generate_series))  ) from generate_series(0,12);
     pageno | count
    --------+-------
          0 |   107
          1 |   107
          2 |   107
          3 |   107
          4 |    84
          5 |     3
          6 |     3
          7 |     3
          8 |     3
          9 |     3
         10 |     3
         11 |     3
         12 |     3
    

    该空间仍在使用,并且元组仍然在那里。 但是,我们可以通过检查t_xmax的有效性来检查不再使用的元组。实际上,根据文档,如果XMAX无效,则该行是最新版本:

    […] a tuple is the latest version of its row iff XMAX is invalid or t_ctid points to itself (in which case, if XMAX is valid, the tuple is either locked or deleted). […]
    
     (from htup_details.h lines 87-89).
    

    我们必须对第12位(2048,或0x0800)检查信息进行检查。

    #define HEAP_XMAX_INVALID       0x0800  /* t_xmax invalid/aborted */
    
    lob_test=# select generate_series as pageno, 
      (select count(*) from heap_page_items(get_raw_page('pg_largeobject',generate_series))
      where t_infomask::bit(16) & x'0800'::bit(16) = x'0800'::bit(16)) from generate_series(0,12);
     pageno | count
    --------+-------
          0 |   107
          1 |   107
          2 |   107
          3 |   107
          4 |    84
          5 |     0
          6 |     0
          7 |     0
          8 |     0
          9 |     0
         10 |     0
         11 |     0
         12 |     0
    

    大对象被分割成压缩的chunk,其内部行为与常规行相同!

    如果我们导入另一个lob,我们会看到空间没有被重用:

    lob_test=# lo_import '/tmp/randoms';
    lo_import 16520
    lob_test=# select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              4235264
    (1 row)
    

    将元组标记为可重用是vacuum的工作:

    lob_test=# vacuum pg_largeobject;
    VACUUM
    
    lob_test=# select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              4235264
    (1 row)
    

    常规的vacuum不会释放空出空间,但空间现在可以重复使用:

    lob_test=# select generate_series as pageno,
     (select count(*) from heap_page_items(get_raw_page('pg_largeobject',generate_series))
     where t_infomask::bit(16) & x'0800'::bit(16) = x'0800'::bit(16)) from generate_series(0,12);
     pageno | count
    --------+-------
          0 |   107
          1 |   107
          2 |   107
          3 |   107
          4 |    84
          5 |     0
          6 |     0
          7 |     0
          8 |     0
          9 |     0
         10 |     0
         11 |     0
         12 |     0
    
    lob_test=# lo_import '/tmp/randoms';
    lo_import 16521
    lob_test=#
    
    lob_test=#  select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              4235264
    (1 row)
    
    -- same size as before!
    
    lob_test=#  select generate_series as pageno, 
    (select count(*) from heap_page_items(get_raw_page('pg_largeobject',generate_series)) 
     where t_infomask::bit(16) & x'0800'::bit(16) = x'0800'::bit(16)) from generate_series(0,12);
     pageno | count
    --------+-------
          0 |   107
          1 |   107
          2 |   107
          3 |   107
          4 |    84
          5 |     3
          6 |     3
          7 |     3
          8 |     3
          9 |     3
         10 |     3
         11 |     3
         12 |     3
    

    如果我们再次unlink 这个lob对象,执行full vacuum,空闲就被释放了:

    lob_test=# lo_unlink 16521
    lo_unlink 16521
    lob_test=#  select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              4235264
    (1 row)
    
    lob_test=# vacuum full pg_largeobject;
    VACUUM
    lob_test=#  select pg_relation_size('pg_largeobject');
     pg_relation_size
    ------------------
              2842624
    (1 row)
    

      

    原文:

    http://www.ludovicocaldara.net/dba/pgsql-lo-space-usage-part-2/

  • 相关阅读:
    Number Sequence
    不容易系列之(3)—— LELE的RPG难题
    又见回文
    统计元音
    数列
    regular expression
    野兽男孩
    GameStd
    boost and qt compile.
    kde4 + compiz只有两个桌面的问题
  • 原文地址:https://www.cnblogs.com/abclife/p/13790588.html
Copyright © 2020-2023  润新知