postgres 是否有效地重用已删除行的空间?

Jac*_*las 4 postgresql vacuum postgresql-9.3

文档

在 PostgreSQL 中,行的 UPDATE 或 DELETE不会立即删除该的旧版本[...] 但最终,任何事务都不再对过时或删除的行版本感兴趣。然后必须回收它占用的空间以供新行重用,以避免磁盘空间需求的无限增长。这是通过运行 VACUUM来完成

当vacuum运行时,它是否通过重写整个块来有效地释放被删除行占用的空间,或者只有当新行小于为它们让路的已删除行时,才会在新行适合可用“孔”时发生块碎片?

Jac*_*las 8

VACUUM 重写整个块,有效地打包剩余的行并留下一个连续的可用空间块(尽管这个空间没有归零并且物理磁盘文件可能包含已删除行的残余,当然这些行对数据库用户)。

测试架构:

--#psql postgres postgres
select oid from pg_database where datname='postgres';
/*
  oid
-------
 12035
*/
create schema stack;
set search_path=stack;
create table foo(bar text);
insert into stack.foo(bar) values('row 1');
insert into stack.foo(bar) values('row 2');
checkpoint;
select * from foo;
/*
  bar
-------
 row 1
 row 2
*/
select relfilenode
from pg_class c join pg_namespace n on n.oid=c.relnamespace
where nspname='stack' and relname='foo';
/*
 relfilenode
-------------
      446488
*/
Run Code Online (Sandbox Code Playgroud)

表备份文件的物理内容:

xxd -a /var/lib/postgresql/9.3/main/base/12035/446488

0000000: 3800 0000 f093 9d83 0000 0000 2000 c01f  8........... ...
0000010: 0020 0420 0000 0000 e09f 3c00 c09f 3c00  . . ......<...<.
0000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
*
0001fc0: 2176 4c14 0000 0000 0000 0000 0000 0000  !vL.............
0001fd0: 0200 0100 0208 1800 0d72 6f77 2032 0000  .........row 2.. <---- this is row 2
0001fe0: 2176 4c14 0000 0000 0000 0000 0000 0000  !vL.............
0001ff0: 0100 0100 0208 1800 0d72 6f77 2031 0000  .........row 1..
Run Code Online (Sandbox Code Playgroud)

删除和真空:

delete from foo where bar='row 1';
vacuum stack.foo;
checkpoint;
Run Code Online (Sandbox Code Playgroud)

表备份文件的物理内容:

xxd -a /var/lib/postgresql/9.3/main/base/12035/446488

0000000: 3800 0000 e8b5 9e83 0000 0500 2000 e01f  8........... ...
0000010: 0020 0420 0000 0000 0000 0000 e09f 3c00  . . ..........<.
0000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
*
0001fc0: 2176 4c14 0000 0000 0000 0000 0000 0000  !vL.............
0001fd0: 0200 0100 0209 1800 0d72 6f77 2032 0000  .........row 2.. <---- this is free space
0001fe0: 2176 4c14 0000 0000 0000 0000 0000 0000  !vL.............
0001ff0: 0200 0100 0209 1800 0d72 6f77 2032 0000  .........row 2..
Run Code Online (Sandbox Code Playgroud)

插入新行:

insert into stack.foo(bar) values('row 3');
checkpoint;
Run Code Online (Sandbox Code Playgroud)

表支持文件的最终物理内容:

xxd -a /var/lib/postgresql/9.3/main/base/12035/446488

0000000: 3800 0000 c8ec 9e83 0000 0100 2000 c01f  8........... ...
0000010: 0020 0420 0000 0000 c09f 3c00 e09f 3c00  . . ......<...<.
0000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
*
0001fc0: 2476 4c14 0000 0000 0000 0000 0000 0000  $vL.............
0001fd0: 0100 0100 0208 1800 0d72 6f77 2033 0000  .........row 3.. <---- this is row 3
0001fe0: 2176 4c14 0000 0000 0000 0000 0000 0000  !vL.............
0001ff0: 0200 0100 0209 1800 0d72 6f77 2032 0000  .........row 2..
Run Code Online (Sandbox Code Playgroud)

清理:

drop schema stack cascade;
Run Code Online (Sandbox Code Playgroud)