暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Postgresql MVCC机制及VACUUM新发现

原创 qi_yu 2021-06-14
1357

MVCC的工作机制

更新和删除数据时,并不是直接删除行的数据,而是更新行的头部信息中的xmax

  1. 创建测试表
postgres=# create table iso\_test(id int,info text);
  1. 插入数据
postgres=# truncate iso_test ;
TRUNCATE TABLE
postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current 
--------------
          562
(1 row)

postgres=# insert into iso_test values(1,'test');
INSERT 0 1
postgres=# SELECT
postgres-# lp AS "行指针",
postgres-# lp_off AS "行指针偏移量",
postgres-# t_xmin AS "插入事务的ID",
postgres-# t_xmax AS "删除事务的ID",
postgres-# t_ctid AS "插入命令的ID",
postgres-# t_data AS "数据本身"
postgres-# FROM heap_page_items(get_raw_page('iso_test',0));
 行指针 | 行指针偏移量 | 插入事务的ID | 删除事务的ID | 插入命令的ID |       数据本身       
--------+--------------+--------------+--------------+--------------+----------------------
      1 |         8152 |          562 |            0 | (0,1)        | \x010000000b74657374
(1 row)
postgres=# end;
COMMIT

  1. 删除数据

    会将xmax的值设置为当前事务的xid

postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current 
--------------
          563
(1 row)

postgres=# delete from iso_test where id=1;
DELETE 1
postgres=# SELECT
postgres-# lp AS "行指针",
postgres-# lp_off AS "行指针偏移量",
postgres-# t_xmin AS "插入事务的ID",
postgres-# t_xmax AS "删除事务的ID",
postgres-# t_ctid AS "插入命令的ID",
postgres-# t_data AS "数据本身"
postgres-# FROM heap_page_items(get_raw_page('iso_test',0));
 行指针 | 行指针偏移量 | 插入事务的ID | 删除事务的ID | 插入命令的ID |       数据本身       
--------+--------------+--------------+--------------+--------------+----------------------
      1 |         8152 |          562 |          563 | (0,1)        | \x010000000b74657374
(1 row)

postgres=# end;
COMMIT

  1. 更新数据,实际上就是先删除原来的行,再插入新行
postgres=# insert into iso_test values(2,'new');
INSERT 0 1
postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current 
--------------
          565
(1 row)

postgres=# select * from iso_test; 
 id | info 
----+------
  2 | new
(1 row)

postgres=# SELECT
postgres-# lp AS "行指针",
postgres-# lp_off AS "行指针偏移量",
postgres-# t_xmin AS "插入事务的ID",
postgres-# t_xmax AS "删除事务的ID",
postgres-# t_ctid AS "插入命令的ID",
postgres-# t_data AS "数据本身"
postgres-# FROM heap_page_items(get_raw_page('iso_test',0));
 行指针 | 行指针偏移量 | 插入事务的ID | 删除事务的ID | 插入命令的ID |       数据本身       
--------+--------------+--------------+--------------+--------------+----------------------
      1 |         8152 |          562 |          563 | (0,1)        | \x010000000b74657374
      2 |         8120 |          564 |            0 | (0,2)        | \x02000000096e6577
(2 rows)

postgres=# update iso_test set info='NEW' where id=2;
UPDATE 1
postgres=# SELECT                                    
lp AS "行指针",
lp_off AS "行指针偏移量",
t_xmin AS "插入事务的ID",
t_xmax AS "删除事务的ID",
t_ctid AS "插入命令的ID",
t_data AS "数据本身"
FROM heap_page_items(get_raw_page('iso_test',0));
 行指针 | 行指针偏移量 | 插入事务的ID | 删除事务的ID | 插入命令的ID |       数据本身       
--------+--------------+--------------+--------------+--------------+----------------------
      1 |         8152 |          562 |          563 | (0,1)        | \x010000000b74657374
      2 |         8120 |          564 |          565 | (0,3)        | \x02000000096e6577
      3 |         8088 |          565 |            0 | (0,3)        | \x02000000094e4557
(3 rows)

postgres=# end;
COMMIT

如果一张表中,反复进行插入和删除操作,表很容易被撑大

VACUUM

回收页面上已经执行UPDATE和DELETE操作的空间

postgres=# VACUUM iso_test ;
VACUUM

查看页面结构
image.png

执行UPDATE和DELETE操作后的空间被回收,但是空间并未释放,等下一条数据插入占用空间

postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current 
--------------
          566
(1 row)

postgres=# insert into iso_test values(1,'test');
INSERT 0 1
postgres=# end;
COMMIT

观察页面结构
image.png

再次插入数据

postgres=# begin;
BEGIN
postgres=# select txid_current();
 txid_current 
--------------
          567
(1 row)

postgres=# insert into iso_test values(3,'postgres');
INSERT 0 1
postgres=# end;
COMMIT

再次观察表结构
image.png

  • 新发现:

第二条数据的空间未被使用,而是新分配了空间,通过进行多次实验发现,执行VACUUM操作之后,UPDATE的数据空间无法被重用,DELETE的数据空间可以被重用
那么在实际生产中,如果一张表频繁进行UPDATE操作,只进行VACUUM是无法进行空间重用的

最后修改时间:2023-06-25 16:13:18
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论