大數據“復活”記
727
2025-03-31
vacuum簡介 :
對于Gaussdb中的行存表,在更新元組或者刪除元組后,舊版本的數據仍然存在,僅在元組頭信息中標記了刪除或更新的事務號(xmax)。對于更新和刪除操作頻繁的表,會存在大量垃圾數據,導致磁盤空間的浪費和查詢掃描時額外的IO開銷,需要定期執行清理操作(vacuum)來控制行存表以及表上索引的膨脹。
vacuum 操作的內部原理:
Vacuum 的主要步驟:
移除死亡元組并對滿足條件的老元組執行frozen操作。
移除指向死亡元組的索引元組,更新對應表的fsm 和 vm 文件
FSM: free space map 空閑空間映射文件,插入數據時會根據該文件來選擇合適的page.
VM: visibility map 可見性映射文件,后續vacuum時會根據該文件來選擇是否掃描某個page,提高vacuum效率;同時在進行index-only-scan時也會使用該文件來提高可見性判斷的效率)。
更新統計數據pg_stat_all_tables。 Linepointer 不會被移除,用于在之后復用。
示意圖如下:
vacuum 之前
vacuum 之后
為什么vacuum后表還是繼續膨脹
Oldestxmin的推進
vacuum 只能清理掉當前全局存活的最老事務(OldestXmin)之前的事務所產生的垃圾數據,所以如果仍然存在老事務的話(比如長事務或者長sql的存在),新事務所產生的垃圾數據并不會被vacuum立即清理。例如:
會話1:新建表row_tbl并插入一條數據,起一個事務先不提交
gaussdb=# create table row_tbl(a int, b int); CREATE TABLE gaussdb=# insert into row_tbl values(1,1); INSERT 0 1 gaussdb=# begin; BEGIN gaussdb=# SELECT txid_current_snapshot(); txid_current_snapshot ----------------------- 210115:210115: (1 row) gaussdb=# SELECT txid_current(); txid_current -------------- 210115 (1 row)
會話2:刪除數據后做vacuum清理操作,再次插入數據,數據也沒有復用之前空間;查詢視圖可以發現垃圾數據并沒有被清理掉。
gaussdb=# select ctid,* from row_tbl; ctid | a | b -------+---+--- (0,1) | 1 | 1 (1 row) gaussdb=# delete row_tbl; DELETE 1 gaussdb=# SELECT txid_current_snapshot(); txid_current_snapshot ----------------------- 210115:210122: (1 row) gaussdb=# vacuum row_tbl; VACUUM gaussdb=# insert into row_tbl values(2,2); INSERT 0 1 gaussdb=# select ctid,* from row_tbl; ctid | a | b -------+---+--- (0,2) | 2 | 2 (1 row) gaussdb=# select n_dead_tup, last_vacuum from pg_stat_all_tables where relname='row_tbl'; n_dead_tup | last_vacuum ------------+------------------------------- 1 | 2021-06-10 20:04:58.987631+08 (1 row)
會話1:將會話1的事務結束再執行vacuum,查詢視圖可以發現沒有死亡元組,插入數據可以發現復用了舊的空間(即ctid是(0,1)的空間)。
gaussdb=# SELECT txid_current_snapshot(); txid_current_snapshot ----------------------- 210136:210136: (1 row) gaussdb=# vacuum row_tbl; VACUUM gaussdb=# select n_dead_tup, last_vacuum from pg_stat_all_tables where relname='row_tbl'; n_dead_tup | last_vacuum ------------+------------------------------- 0 | 2021-06-10 20:09:10.516564+08 (1 row) gaussdb=# insert into row_tbl values(3,3); INSERT 0 1 gaussdb=# select ctid,* from row_tbl; ctid | a | b -------+---+--- (0,1) | 3 | 3 (0,2) | 2 | 2 (2 rows)
LinePointer狀態還未處于unused
元組被刪除后,只有當vacuum將元組的LinePointer(或者叫item pointer, 指向具體的元組)置為LP_UNUSED狀態后,該LinePointer才有可能在新插入數據時復用。
Fsm還未生成
插入數據時,依賴fsm文件來選擇可用的page,如果fsm沒有生成則會導致使用新的page而不是復用舊的。
批量導入
在舊版本Gaussdb中,對表進行批量插入數據的操作時,會直接申請新的page來插入數據。所以在某些場景下雖然vacuum后清理了臟數據,但由于業務場景以批量插入為主,導致vacuum對膨脹的控制效果并不理想。目前已經支持批量插入數據時對空間的復用。
一些建議與總結
盡量避免長事務,可以通過視圖pg_running_xacts查看是否有老事務沒有結束或者兩階段事務殘留
定期做vacuum來及時回收垃圾空間
對于已經膨脹的索引可以通過reindex來縮小大小。
vacuum能清理垃圾數據,但無法將這些空間還給操作系統,對于已經膨脹的表只能通過vacuum full來縮小大小。
想了解GuassDB(DWS)更多信息,歡迎微信搜索“GaussDB DWS”關注微信公眾號,和您分享最新最全的PB級數倉黑科技~
EI智能體 Gauss AP 數據倉庫服務 GaussDB(DWS)
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。