Concurrent Vacuum은 데이터베이스 내부 전체 테이블 또는 특정 테이블들에 대해 다음과 같은 프로세스를 수행한다
Dead tuple 제거
old txid freeze 화
그 외
각 Vacuum 대상 테이블을 순회하며 크게 3가지 동작을 진행하고, 마지막으로 후처리 작업을 진행한다
각 테이블 순회 작업 진행
사전 동작
ShareUpdateExclusiveLock lock 획득
(다른 트랜잭션들 테이블 조회 가능)1번째 동작
모든 페이지의 모든 dead tuple 스캔
필요 시 old tuple freeze 진행
dead tuple을 가리키는 index tuple 제거
- PostgreSQL이 dead tuple과 old tuple을 추리기 위해 테이블을 스캔
maintenance_work_mem
이라는 로컬메모리에 저장- 추려낸 dead tuple 리스트를 참조하여 index 튜플 제거
- clean stage 라고 부름
- cost가 비쌈
- 11 버전에서 성능개선 이루어짐
- 10 이하 버전에서는 항상 cleanup stage가 실행되었지만, 11버전부터는 인덱스가 B-tree 일때, cleanup stage 실행 여부를
vacuum_cleanup_index_scale_factor
라는 config 파라매터에 의해 결정maintenance_work_mem
사이즈가 full이고 스캔이 완료되지 않을 시, 일단 현재 진행사항을 미루고 다음 단계를 진행한다 (추후 멈췄던 단계로 돌아와 다시 작업 진행)2번째 동작
각 페이지 순회 작업 진행dead tuple 제거
live tuple 위치 재할당 후 FSM,VM 업데이트
- 페이지 별로 차례대로 진행
- dead tuple 지운 후 live tuple의 데이터 위치 정리(defragmentation)
- dead tuple을 가리키던 line pointer는 제거 되지 않는다
- 제거 되지 않고 재활용된다
- 제거되면 관련된 모든 인덱스 튜플이 전부 업데이트 되어야 하기 때문
3번째 동작
index 정리
마지막 페이지에 live tuple이 없다면 마지막 페이지 truncate 진행
테이블의 시스템 카탈로그와 통계 업데이트사후 동작
ShareUpdateExclusiveLock lock 릴리즈
후처리
시스템 카탈로그 및 통계 업데이트
clog 내부 불필요한 페이지와 파일을 제거
Concurrent Vacuum 수도 코드
reference
(1) FOR each table
(2) Acquire a ShareUpdateExclusiveLock lock for the target table
/* The first block */
(3) Scan all pages to get all dead tuples, and freeze old tuples if necessary
(4) Remove the index tuples that point to the respective dead tuples if exists
/* The second block */
(5) FOR each page of the table
(6) Remove the dead tuples, and Reallocate the live tuples in the page
(7) Update FSM and VM
END FOR
/* The third block */
(8) Clean up indexes
(9) Truncate the last page if possible
(10) Update both the statistics and system catalogs of the target table
Release the ShareUpdateExclusiveLock lock
END FOR
/* Post-processing */
(11) Update statistics and system catalogs
(12) Remove both unnecessary files and pages of the clog if possible
PARALLEL Option
_vm
라는 suffix가 이름에 붙음
image reference
(VM을 통한 dead tuple 여부 체크 및 페이지 skip 예시)
image reference
(다른 진행중인 트랜잭션은 없고, txid = 50002500인 트랜잭션이 Vacuum을 수행하는 예시)
lazy mode에서 skip 되는 페이지들을 포함하여 전체 freeze 수행
pg_database.datfrozenxid < OldestXmin - vacuum_freeze_table_age 만족 시 eager mode 발동
pg_database.datfrozenxid
시스템 카탈로그 pg_database에 저장하는 로우 칼럼
각 데이터베이스의 oldest frozen txid를 저장
9.5버전 기준 데이터베이스 클러스터 신규 설치 시 초기 값은 1821
vacuum 작업 종료 전, 필요 시 pg_database.datfrozenxid 값 업데이트
데이터베이스 내 모든 테이블(시스템 카탈로그 테이블 포함)이 frozen 되었을 때, pg_class.relfrozenxid 의 최솟값을 저장
image reference
(relfrozenxid가 업데이트 되었을 때 해당 데이터베이스의 datfrozenxid 변화 예시)
vacuum_freeze_table_age
테이블 freeze 후, 각 테이블의 pg_class.relfrozenxid 값 업데이트 함
image reference
(다른 진행중인 트랜잭션은 없고, txid = 150002000인 트랜잭션이 Vacuum을 수행하는 예시)
FREEZE option
pg_database.datfrozenxid가 업데이트((eager mode)) 될 때 마다, 필요 없는 clog(트랜잭션 상태 저장) 파일(최대 256kb, 0000부터 시작) 및 페이지(각 8kb in 파일) 제거
image reference
(최소 datfrozenxid 값이 저장된 0002 파일 미만의 0000, 0001 파일이 제거되는 예시)
다음 조건 중 하나라도 만족하는 테이블이 있다면 autovacuum을 수행한다
1. current_txid < relfrozenxid + autovacuum_freeze_max_age
- relfrozenxid: pg_class 카탈로그에 저장된 해당 테이블 값
- autovacuum_freeze_max_age: config 파라매터(default: 200000000)
2. dead tuple 개수 > autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor x reltuples
- autovacuum_vacuum_threshold: config 파라매터 (default: 50)
- autovacuum_vacuum_scale_factor: config 파라매터 (default: 0.2)
- reltuples: 해당 테이블의 튜플 개수
3. 테이블에 삽입된 tuple 개수 > autovacuum_vacuum_insert_threshold + autovacuum_vacuum_insert_scale_factor x reltuples
- autovacuum_vacuum_insert_threshold: config 파라매터 (default: 1000)
- autovacuum_vacuum_insert_scale_factor: config 파라매터 (default: 0.2)
- reltuples: 해당 테이블의 튜플 개수
- 이 조건은 PostgreSQL 버전 13부터 추가
4. mod_since_analyze > autovacuum_analyze_threshold + autovacuum_analyze_scale_factor x reltuples
- analyze process 추가로 수행
- mod_since_analyze: 직전 analyze process 시점부터 수정된 튜플의 수
- autovacuum_vacuum_analyze_threshold: config 파라매터 (default: 50)
- autovacuum_vacuum_analyze_scale_factor: config 파라매터 (default: 0.1)
- reltuples: 해당 테이블의 튜플 개수
Concurrent Vacuum 수행해도, 테이블 크기는 경감되지 않고 디스크 공간이 낭비되는 문제를 극복
image reference
(concurrent vacuum 후 잉여 페이지 공간에 대한 극단적인 예시)
Full Vacuum 수행 시, 그 어떤 read/write 트랜잭션도 해당 테이블에 접근할 수 없다
image reference
(full vacuum 예시)
(1) FOR each table
(2) Acquire AccessExclusiveLock lock for the table
(3) Create a new table file
(4) FOR each live tuple in the old table
(5) Copy the live tuple to the new table file
(6) Freeze the tuple IF necessary
END FOR
(7) Remove the old table file
(8) Rebuild all indexes
(9) Update FSM and VM
(10) Update statistics
Release AccessExclusiveLock lock
END FOR
(11) Remove unnecessary clog files and pages if possible