cluster、update、delete在死元组清理上的作用
简介
在 PostgreSQL 中,为了支持 MVCC(多版本并发控制),对表中行的更新和删除并不会立刻移除旧的数据行,而是:
更新操作:创建一个新的行版本(tuple),原来的行变成“死元组”。
删除操作:标记该行为删除(也是变成死元组),但仍然保留在表中一段时间。
因此,死元组就是对其他事务来说已经无效的旧数据行。
很多人可能不知道,除了vacuum会清理死元组,实际上update、delete 也会清理死元组。
update
update在特定情况下也会将死元组清理掉 ,创建一个填充率为100的,并禁用其autovacuum
DROP TABLE IF EXISTS test_fillfactor;
CREATE TABLE test_fillfactor (
id SERIAL PRIMARY KEY,
content TEXT
) WITH (fillfactor = 100,autovacuum_enabled = false, toast.autovacuum_enabled = false);
向其中插入刚刚分页的数据量
INSERT INTO test_fillfactor (content)
SELECT repeat('a', 111) || generate_series(1 ,57);
我们使用pg_dirtyread去看其死元组情况。
create extension pg_dirtyread;
SELECT txid_current(),t.* FROM pg_dirtyread('test_fillfactor') as t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id integer,content TEXT) order by ctid desc limit 5 ;
此时我们更新第一页的最后一条数据和新页第一条数据(id=55和id=56),由于填充因子是100 此时新的数据并不会追加的页末尾。
checkpoint; --执行检查点,让其fsync
UPDATE test_fillfactor SET content = repeat('b', 111)||'(1.1)' WHERE id=56;
UPDATE test_fillfactor SET content = repeat('b', 111)||'(0.55)' WHERE id=55;
SELECT txid_current(),t.* FROM pg_dirtyread('test_fillfactor') as t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id integer,content TEXT) order by ctid desc limit 5 ; --此时的死元组依然存在。
当执行一段查询之后
SELECT txid_current(),xmin, xmax, ctid, * FROM test_fillfactor order by ctid desc limit 5 ;
SELECT txid_current(),t.* FROM pg_dirtyread('test_fillfactor') as t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id integer,content TEXT) order by ctid desc limit 5 ; --此时的死元组id=55的便消失。
此时通过系统视图查看其仍然有两条死元组,其中一条update 是n_tup_hot_upd,另一条并没有追加到也末尾,(0.55)数据追加到了(1,4)。
select * from pg_stat_user_tables where relname ='test_fillfactor';
我们再通过pageinspect跟踪看一下0页的数据情况