PostgreSQL的大对象以及空间使用 (2)
2020-10-11 10:22 abce 阅读(519) 评论(1) 收藏 举报在上一篇文章中,展示了插入大对象后,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)
如果您阅读了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元组。
让我们检查是否正确:
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
[…] 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_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)
原文:

浙公网安备 33010602011771号