Oracle事務(wù)的回滾缚陷,通過回滾段保存原有數(shù)據(jù)實現(xiàn),但往核,PG沒有回滾段箫爷!以下以Update操作為例,說明PG實現(xiàn)機(jī)制上存在的空間暴漲問題聂儒。
在執(zhí)行Update時虎锚,Oracle就地更新,如出現(xiàn)原block空間不足的情況衩婚,通過link的方式鏈接至新block上(不精確窜护,大體表述);PG的Update非春,不是原地更新柱徙,而是保留原有數(shù)據(jù)缓屠,通過新增新的tuple(數(shù)據(jù)行)保存新增數(shù)據(jù),原有數(shù)據(jù)通過Vacuum機(jī)制清理护侮。Vacuum機(jī)制需要滿足MVCC(多版本并發(fā)控制)的要求敌完,在某些情況下,不會清理“垃圾”數(shù)據(jù)概行,在事務(wù)繁忙的時候?qū)е聲?dǎo)致數(shù)據(jù)表空間不斷增長蠢挡。
--------------------------- Session A
-- 開啟事務(wù)
begin;
-- 查詢當(dāng)前事務(wù)
select txid_current();
txid_current
--------------
? ? ? 1500987
(1 row)
-- 什么都不做,會導(dǎo)致Vacuum不能清理“垃圾”數(shù)據(jù)
--------------------------- Session B
-- 開啟事務(wù)
begin;
select txid_current();
txid_current
--------------
? ? ? 1500988
(1 row)
-- 創(chuàng)建表&插入100數(shù)據(jù)
drop table if exists t1;
create table t1(id int,c1 varchar(50));
insert into t1 select generate_series(1,100),'#TESTDATA#';
------------------- 以上操作省略輸出
select txid_current();
txid_current
--------------
? ? ? 1500988
(1 row)
-- 提交事務(wù)
end;
-- 查看數(shù)據(jù)表
select ctid, xmin, xmax, cmin, cmax,id from t1;
testdb=# select ctid, xmin, xmax, cmin, cmax,id from t1;
? ctid? |? xmin? | xmax | cmin | cmax | id?
---------+---------+------+------+------+-----
(0,1)? | 1500988 |? ? 0 |? ? 4 |? ? 4 |? 1
(0,2)? | 1500988 |? ? 0 |? ? 4 |? ? 4 |? 2
(0,3)? | 1500988 |? ? 0 |? ? 4 |? ? 4 |? 3
(0,4)? | 1500988 |? ? 0 |? ? 4 |? ? 4 |? 4
......
-- 查看數(shù)據(jù)占用空間
\set v_tablename t1
SELECT pg_size_pretty( pg_total_relation_size(:'v_tablename') );
testdb=# SELECT pg_size_pretty( pg_total_relation_size(:'v_tablename') );
pg_size_pretty
----------------
8192 bytes
(1 row)
-- 使用pgbench進(jìn)行壓力測試凳忙,不斷更新數(shù)據(jù)
cat update.sql
\set rowid random(1,100)
begin;
update t1 set c1=c1||:rowid where id= :rowid;
end;
pgbench -c 2 -C -f ./update.sql -j 1 -n -T 600 -U xdb testdb
-- 一段時間后查看數(shù)據(jù)占用空間
SELECT pg_size_pretty( pg_total_relation_size(:'v_tablename') );
testdb=# SELECT pg_size_pretty( pg_total_relation_size(:'v_tablename') );
pg_size_pretty
----------------
? 1344 kB
(1 row)
從原來的8192 Bytes變成了1344 KB业踏,空間“暴漲”。
究其原因涧卵,是因為PG的MVCC實現(xiàn)機(jī)制導(dǎo)致的:如果存在某個事務(wù)勤家,在更新數(shù)據(jù)前開啟,那么更新數(shù)據(jù)時前后的數(shù)據(jù)都要存儲柳恐,無論更新多少次都要存儲伐脖!