本次測試數據庫版本為MogDB/openGauss3.0,測試undo相關的參數會怎樣影響undo目錄中舊版本數據自動回收的能力,強制回收會不會丟數據。
undo目錄結構圖

數據目錄中的undo目錄下有三個目錄和一個undometa文件,undometa是undo的元數據文件,permanent是存儲undo的持久化數據的,這部分數據丟失,會導致ustore表數據的不一致。因此$PGDATA/undo目錄不能隨便刪除。
測試undo參數
-
undo_retention_time
參數說明: 設置undo舊版本保留時間,默認不保留舊版本。 -
undo_space_limit_size
參數說明: 用于控制undo強制回收閾值,達到閾值的80%啟動強制回收。 -
undo_limit_size_per_transaction
參數說明: 用于控制單事務undo分配空間閾值,達到閾值時事務報錯回滾。
undo_retention_time的測試
- undo_retention_time值為0,undo最大空間800MB,對ustore表做增刪改操作,同時undo統計信息

select gs_stat_undo();
通過undo系統函數 gs_stat_undo() 可以看到在ustore表數據修改時undo目錄就一直在增大,事務提交,執行成功就不再增大。大概過了5秒 undo目錄里的舊數據就被清理,又回到原先值。
查看undo目錄大小

查看這時間段表的CSN是不存在的
SELECT * FROM gs_txn_snapshot where snptime between '2022-08-16 09:00:00' and '2022-08-16 10:00:00';
snptime | snpxmin | snpcsn | snpsnapshot
---------+---------+--------+-------------
(0 rows)
undo_retention_time參數起到了及時清理舊版本數據的作用,設置為0s undo目錄清理舊版本數據的特別快,約等于不存儲舊版本數據,空間上節省了不少。但是舊版本數據刪除了,基于MVCC的閃回表和閃回查詢就無法做到,所以這樣設置不利于基于MVCC的閃回恢復。
- undo_retention_time值為60s,undo最大空間800MB,對ustore表做DML
MogDB=# create table t1 (id int , name text);
CREATE TABLE
MogDB=# insert into t1 values (generate_series(1,1000000),md5(random()::text));
INSERT 0 1000000
MogDB=# select gs_stat_undo();
gs_stat_undo
-------------------------------------------------------------
(4,"1 : 40, 0 : 0, 0 : 0",45,640,42576,42618,0,0,3053,3004)
(1 row)
-- 隔半分鐘再執行
MogDB=# insert into t1 values (generate_series(1,1000000),md5(random()::text));
INSERT 0 1000000
MogDB=# select gs_stat_undo();
gs_stat_undo
-------------------------------------------------------------
(4,"1 : 80, 0 : 0, 0 : 0",85,640,42594,42638,0,0,3093,3004)
(1 row)
-- 第一次插入后的一分鐘空間被回收了
MogDB=# select gs_stat_undo();
gs_stat_undo
-------------------------------------------------------------
(4,"1 : 40, 0 : 0, 0 : 0",44,640,42621,42662,0,0,3093,3045)
(1 row)
-- 再過半分鐘第二次insert的空間又被回收
MogDB=# select gs_stat_undo();
gs_stat_undo
-----------------------------------------------------------
(4,"0 : 0, 0 : 0, 0 : 0",4,640,42652,42690,0,0,3093,3085)
(1 row)
上面測試可以看出,多久提交是按照事務提交的時間計算,待夠了60s的事務就會釋放它的舊版本數據。時間短也不利于做基于MVCC的閃回表閃回查詢。
- undo_retention_time值為30000s,undo最大空間800MB,對ustore表做DML
MogDB=# insert into t1 values (generate_series(1,2000000),md5(random()::text));
INSERT 0 2000000
MogDB=# insert into t1 values (generate_series(1,2000000),md5(random()::text));
INSERT 0 2000000
MogDB=# insert into t1 values (generate_series(1,2000000),md5(random()::text));
INSERT 0 2000000
MogDB=# delete t1 where id < 1000000;
DELETE 2999997
MogDB=# select gs_stat_undo();
gs_stat_undo
-----------------------------------------------------------
(4,"0 : 0, 0 : 0, 0 : 0",4,640,42920,44007,0,0,3093,3085)
(1 row)
MogDB=# select gs_stat_undo();
gs_stat_undo
---------------------------------------------------------------
(4,"1 : 224, 0 : 0, 0 : 0",228,640,42920,44365,0,0,3317,3085)
(1 row)
MogDB=# select gs_stat_undo();
gs_stat_undo
---------------------------------------------------------------
(4,"1 : 454, 0 : 0, 0 : 0",458,640,42920,44397,0,0,3547,3085)
(1 row)
MogDB=# select gs_stat_undo();
gs_stat_undo
---------------------------------------------------------------
(4,"1 : 592, 0 : 0, 0 : 0",596,640,42920,44397,0,0,3685,3085)
(1 row)
MogDB=# select gs_stat_undo();
gs_stat_undo
---------------------------------------------------------------
(4,"1 : 397, 0 : 0, 0 : 0",401,640,42920,44397,0,0,3691,3286)
(1 row)
因為回收時間還比較久,undo目錄為了保證舊版本的還能寫入,設置了最大目錄的80%作為閾值,可以看到在接近640MB的時候undo空間有自動清理機制,保證事務還能寫入undo目錄。
undo_limit_size_per_transaction測試1
- 設置undo_limit_size_per_transaction為30M,事務大于這個值會是什么結果。
MogDB=# select COUNT(*) from t1 ;
count
---------
3800001
(1 row)
MogDB=# insert into t1 values (generate_series(1,2000000),md5(random()::text));
ERROR: [RollbackIfUndoExceeds:71]xid 47550, the undo size 31457286 of the transaction exceeds the threshold 31457280.
MogDB=# select COUNT(*) from t1 ;
count
---------
3800001
(1 row)
MogDB=# update t1 set id = 10;
ERROR: [RollbackIfUndoExceeds:71]xid 47620, the undo size 31457316 of the transaction exceeds the threshold 31457280.
MogDB=# select COUNT(*) from t1 where id = 10;
count
-------
4
(1 row)
MogDB=# delete t1 ;
ERROR: [RollbackIfUndoExceeds:71]xid 47677, the undo size 31457376 of the transaction exceeds the threshold 31457280.
MogDB=# select COUNT(*) from t1;
count
---------
3800001
(1 row)
單事務最大閾值的設置,可以讓超過值的事務回滾,不影響到原來的數據。
undo_limit_size_per_transaction測試2
undo_space_limit_size是undo目錄可使用的最大值,我們把undo_limit_size_per_transaction設置比undo最大可用空間都大進行測試。那么undo_limit_size_per_transaction=800MB,undo_limit_size_per_transaction=2G,執行一條超過800MB的事務。

有的時候undo目錄會寫到640MB開始清零,然后繼續進行寫入,事務沒有被中斷,也沒有影響表更新的數據,有的時候會如下,到最大undo目錄大小值還是沒有清理。

雖然undo空間滿了,但不影響其他事務的進行,其他事務會觸發undo目錄全部清理。

報錯表進行查詢報如下錯,數據已經丟失。
openGauss=# select count(*) from t1;
ERROR: snapshot too old! the undo record has been force discard
undo_limit_size_per_transaction的值一定比undo_space_limit_size要小,在openGauss官方的默認配置里undo_limit_size_per_transaction比undo_space_limit_size更小。




