关于PG MVCC原理的一点思考

今天早上骑电屏车上班时突然想到了一个问题,昨天看了些PG的有关MVCC的资料,PG在处理 UPDATE,DELETE 语句时,不会立即删除掉旧的记录,而是将旧的记录保存一段时间,直到VACCUM之后才会真正删除旧的记录,我在想,当DELETE语句时PG保留原有的记录这很好理解,但是当UPDATE时,PG是保留UPDATE的整行记录,还是仅保留那条记录被UPDATE的字段,带着这个疑问,做了以下测试。

创建测试表

创建测试表并插入100万数据

1
2
3
4
mydb=> create table test_7 (id integer, remark varchar(32));  
CREATE TABLE
mydb=> insert into test_7 select generate_series(1,1000000),'aaaaaa';
INSERT 0 1000000

查看表大小和占用PAGE

查看表大小

1
2
3
4
5
mydb=> select pg_size_pretty(pg_relation_size('test_7'));  
pg_size_pretty
----------------
38 MB
(1 row)

这里看出表 test_7 为 38 M。

查看表的page数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
mydb=> /d pg_class  
Table "pg_catalog.pg_class"
Column | Type | Modifiers
-----------------+-----------+-----------
relname | name | not null
relnamespace | oid | not null
reltype | oid | not null
reloftype | oid | not null
relowner | oid | not null
relam | oid | not null
relfilenode | oid | not null
reltablespace | oid | not null
relpages | integer | not null
reltuples | real | not null
reltoastrelid | oid | not null
reltoastidxid | oid | not null
relhasindex | boolean | not null
relisshared | boolean | not null
relistemp | boolean | not null
relkind | "char" | not null
relnatts | smallint | not null
relchecks | smallint | not null
relhasoids | boolean | not null
relhaspkey | boolean | not null
relhasexclusion | boolean | not null
relhasrules | boolean | not null
relhastriggers | boolean | not null
relhassubclass | boolean | not null
relfrozenxid | xid | not null
relacl | aclitem[] |
reloptions | text[] |
Indexes:
"pg_class_oid_index" UNIQUE, btree (oid)
"pg_class_relname_nsp_index" UNIQUE, btree (relname, relnamespace)

mydb=> analyze test_7;
ANALYZE

mydb=> select relname,relpages,reltuples from pg_class where relname='test_7';
relname | relpages | reltuples
---------+----------+-----------
test_7 |4902 | 1e+06
(1 row)

这里可以看出表 test_7 有4902 page。测试UPDATE, 并再次查看表大小和占用 page数

UPDATE表

1
2
3
4
5
6
7
8
9
10
11
mydb=> update test_7 set remark='bbbbbb';  
UPDATE 1000000

mydb=> select relname,relpages,reltuples from pg_class where relname='test_7';
relname | relpages | reltuples
---------+----------+-----------
test_7 | 4902 | 1e+06
(1 row)

mydb=> analyze test_7;
ANALYZE

再次查看表大小和占用PAGE

1
2
3
4
5
6
7
8
9
10
11
mydb=> select relname,relpages,reltuples from pg_class where relname='test_7';  
relname | relpages | reltuples
---------+----------+-----------
test_7 | 9804 | 1e+06
(1 row)

mydb=> select pg_size_pretty(pg_relation_size('test_7'));
pg_size_pretty
----------------
77 MB
(1 row)

从上面看出,表的PAGE数为9804,刚好增加了一倍,这也说明,PG处理UPDATE语句时,也是保留了原有记录的一份,只是在存储上标记为不可读而已,同时也说明,保留的是原有的记录整行,而不只是更新的字段值。

原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/236343.html

(0)
上一篇 2022年1月24日
下一篇 2022年1月24日

相关推荐

发表回复

登录后才能评论