일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- psql 복구
- Goldengate
- PostgreSQL Install
- dblink 삭제
- sql문 전체 출력 방법
- ogg-01028
- db upgrade
- PostgreSQL Parameter 설정 방법
- multitenant
- 19c tde
- 다른계정에서 dblink 삭제방법
- sql문 짤릴 때
- PostgreSQL Parameter
- OGG
- ogg 구성
- pg_dumpall
- Archive delete
- ogg 설치 방법
- PostgreSQL 아키텍처
- PostgreSQL 스키마 관리
- Linux
- PostgreSQL Admin
- 아카이브로그 삭제
- table lock 조치 방법
- oracle error
- PostgreSQL 테이블스페이스 생성 삭제
- PostgreSQL Backup and Recovery
- oracle
- pg_basebackup
- pgcrypto
- Today
- Total
인성장
[PostgreSQL] Vacuum (7) 본문
PostgreSQL Vacuum
Vacuum 이해를 돕기 위해 먼저 PostgreSQL MVCC 동작 방식에 대한 설명을 하겠습니다.
MVCC란?
다중 버전 동시성 제어(Multi-Version Concurrency Control)의 약자로, 동시 접근을 허용하는 데이터베이스에서 동시성을 제어하기 위해 사용하는 방법입니다. MVCC 모델에서 데이터에 접근하는 사용자는 접근한 시점에서의 데이터베이스의 Snapshot을 읽는데, 이 Snapshot 데이터에 대한 변경이 완료될 때(=트랜잭션이 commit 될 때)까지 만들어진 변경사항은 다른 데이터베이스 사용자가 볼 수 없습니다. 만약 동시성 제어 없이 A 사용자가 데이터베이스를 읽는 동시에 B 사용자가 기록을 하려고 한다면, A 사용자는 반쯤 기록되거나 일관성 없는 데이터를 보게 될 가능성이 큽니다. 그래서 PostgreSQL은 MVCC를 구현하기 위해 블록 내 이전 레코드를 모두 남겨두는 방식을 사용합니다.
* Oracle은 Undo Segment라는 것을 이용해 MVCC 모델을 구현합니다.
PostgreSQL MVCC 동작 방식
PostgreSQL는, UPDATE 나 DELETE 쿼리가 순전히 기존 데이터를 변형하거나 삭제하는 방향으로 동작하지 않습니다. 즉, UPDATE 쿼리는 기존에 있던 데이터는 그대로 둔 채 새로운 데이터를 추가하는 방식으로 동작하며, DELETE 쿼리 또한 기존의 데이터를 삭제해야 한다는 표시만 남겨두고 실제로는 삭제하지 않는 방식으로 동작을 합니다.
이것이 PostgreSQL에서 동시접근에 의한 이슈들을 방지하기 위한 MVCC 모델 적용 방식입니다.
아래 예제를 통해 좀 더 자세히 알아보겠습니다.
사원테이블에서 아래 쿼리문이 차례로 수행되었습니다.
UPDATE 사원테이블 SET 부서='생산팀' WHERE 이름='홍길동';
COMMIT;
DELETE FROM 사원테이블 WHERE 이름='김두한';
COMMIT;
1. 사원테이블에서 홍길동씨의 부서명을 품질팀에서 생산팀으로 변경하면 기존 데이터는 유지되고 새로운 데이터가 추가됩니다.
2. 사원테이블에서 김두한씨의 데이터를 삭제하면 삭제데이터란 표시만 남겨두고 실제론 테이블에 남아있게 됩니다.
이처럼 변경되거나 삭제된 데이터들이 테이블에 남아있기 때문에, 변경이 완료된 데이터만 조회가 되도록 해야합니다. 이를 위해 PostgreSQL에서는 각 Tuple마다 생성되거나 변경된 시점을 각 Tuple별로 존재하는 XMIN, XMAX라는 메타데이터 필드에 XID를 기록하여 비교하는 방식을 사용해 어떤 Tuple을 읽을 수 있는지 버전 관리를 하게 됩니다.
* Tuple, Record(레코드), Row(행)와 같이 DBMS별로 사용하는 용어의 차이는 있지만 의미는 모두 동일합니다.
* XID (Transaction ID) : 트랜잭션이 발생한 시점을 식별하기 위한 정보
아래는 XMIN, XMAX 값이 할당되는 상세한 과정입니다.
XMIN
- 데이터를 INSERT하거나 UPDATE하는 시점의 XID가 할당됩니다.
- INSERT의 경우 삽입 된 신규 Tuple의 XMIN에 해당 시점의 XID가 할당됩니다.
- UPDATE의 경우 변경 된 신규 Tuple의 XMIN에 해당 시점의 XID가 할당됩니다.
XMAX
- DELETE하거나 UPDATE하는 시점의 XID가 할당됩니다.
- DELETE의 경우 변경(삭제)되기 이전 Tuple의 XMAX에 해당 시점의 XID가 할당됩니다.
- UPDATE의 경우 변경되기 이전 Tuple의 XMAX에 해당 시점의 XID가 할당됩니다. 여기서 변경 된 신규 Tuple의 XMIN에 변경되기 이전 Tuple의 XMAX에 할당된 같은 XID값이 할당됩니다.
- UPDATE된 신규 Tuple의 XMAX에는 NULL이 할당됩니다.
정리하면, XMAX값이 NULL 인 Tuple의 경우 가장 최신 버전의 데이터를 의미하며, XMAX값이 설정된 Tuple은 해당 시점 과거 버전의 데이터(삭제 및 변경)를 의미합니다. 아래 그림 예제(2)가 바로 테이블을 읽는 시점에 따라 보이는 데이터들을 나타냅니다.
이와 같은 방식으로 PostgreSQL에서 MVCC모델은 레코드 별 XID 비교를 통해 비교적 쉽게 구현할 수 있습니다.
하지만 이러한 구현방식에는 아래와 같이 대표적인 두가지 치명적인 단점이 있습니다.
* 공간 사용의 비효율
Update, Delete가 빈번한 테이블에 대해서는 각 데이터의 이전 버전을 모두 저장해야 하므로 공간 비효율이 커지며 스캔 범위가 늘어나는 부작용이 발생할 수 있습니다. 또한, Oracle처럼 Block단위가 아닌 레코드 단위의 XID 저장 방식은 페이지 내부에 대한 공간 비효율을 야기합니다.
* XID 부족 현상
레코드 별 XID가 4Bytes 라는 점의 또 다른 문제점으로는 43억 개 정도의 Transaction밖에 표현할 수 없다는 것입니다. 이로 인해 43억 XID를 Newer/Older 구조로 나누어 순환식으로 사용하며(모듈로 연산), 오래된 XID의 경우 주기적으로 특수 값(Frozen XID) 세팅을 통해 언제나 가장 오래된 데이터임을 표시해야 합니다.
이러한 일련의 문제들을 해결하기 위해 PostgreSQL은 Vacuum이란 기능을 만들어냈으며, Vacuum을 이용하여 해당 문제점들을 보완했습니다.
Vacuum 이란?
위와 같은 PostgreSQL MVCC 구조로 인해 삭제되거나 변경 처리가 된 기존 데이터들이 테이블에 그대로 남아있는 이른바, Dummy Data 로 남아있게 되는데 이러한 Dummy Data(Dead Tuple)들을 정리해주는 것이 Vacuum입니다.
* Dummy Data(Dead Tuple) : 불필요한, 쓰레기 데이터
Vacuum이 왜 필요할까?
앞서 설명했던 내용대로 PostgreSQL에서 삭제나 변경 처리 된 기존 데이터들이 삭제 되지 않고 더미 형식으로 테이블에 계속 남아있기 때문에 테이블 용량이 계속 증가하여 디스크 사용 가능한 공간이 적어지고 또, 스캔 범위도 늘어나(Disk I/O 증가) 데이터 조회 시 성능이 저하되는 현상이 발생할 수 있습니다. 이와 같은 문제점들을 해소시키기 위해 Vacuum이 필요한 이유라 할 수 있습니다.
Vacuum 사용 방법
Vacuum은 수동 Vacuum 방식과 자동 Vacuum(Autovacuum) 방식으로 나뉩니다. 수동 Vacuum 방식은 사용자가 직접 명령어를 입력하여 동작하게끔 하는 것이며, 자동 Vacuum(Autovacuum) 방식은 말 그대로 자동으로 Vacuum을 수행해주는 것입니다.
수동 Vacuum
-- DB full vacuum
postgres=# vacuum full analyze;
-- DB 간단하게 vacuum
postgres=# vacuum verbose analyze;
-- 특정 테이블만 간단하게 vacuum
postgres=# vacuum analyze [table_name];
-- 특정 테이블만 vacuum full
postgres=# vacuum full [table_name];
일반적인 Vacuum 명령어의 경우 FSM(Free Space Map)이라는 메모리 공간에서 구 버전 데이터가 차지하는 공간을 재사용 가능한 상태로 변경하는데 실제 OS 물리적인 디스크 공간까지 확보해주진 않습니다. 만약, 구 버전 데이터가 차지하는 물리적 디스크 공간을 확보해야 한다면, Vacuum Full 명령어를 사용하여야 합니다.
단, Vacuum Full 명령어 수행 시 해당 데이터베이스에 LOCK이 걸리므로 운영중인 데이터베이스에서 사용 시 주의하셔야 합니다.
자동 Vacuum (Autovacuum)
Autovacuum은 데이터베이스나 테이블 단위로 설정만 해두면 자동으로 autovacuum launcher 프로세스에 의해 vacuum이 처리되게끔 해줍니다. 테이블 단위로 각각 Autovacuum을 설정해 줄 수 있지만, 관리가 어렵기 때문에 일반적으로 postgresql.conf 라는 파일에 Autovacuum 관련 파라미터 값을 설정하여 전체 데이터베이스에 적용되게끔 사용합니다.
-- Dead Tuple 20,000 건 이상 시 Autovacuum 수행되게끔 설정
$ vi postgresql.conf
...
autovacuum_vacuum_scale_factor = 0.0
autovacuum_vacuum_threshold = 20000
...
-- 변경내용 적용위해 reload
$ $PG_HOME/bin/pg_ctl reload -D $PGDATA
Autovacuum 관련 파라미터 설정값이 어떻게 되느냐에 따라 Dummy Data(Dead Tuple)의 증가를 얼마나 억제시킬 수 있을지가 결정되기 때문에 간단하게 위 설정값을 예로 Autovacuum 최적화 방법에 대해 말씀드리겠습니다.
Autovacuum을 최적화하는 가장 간단한 방법은 autovacuum_vacuum_scale_factor 값을 0 으로 설정하는 것입니다.
이유는 Autovacuum이 수행되는 시점을 정하는 조건이 있는데 그 조건식은 아래와 같습니다.
( Table Total Row 수 * autovacuum_vacuum_scale_factor ) + autovacuum_vacuum_threshold
= 나온 값 이상의 Dummy Data(Dead Tuple) 발생 시 Autovacuum 수행
이 때문에, autovacuum_vacuum_scale_factor 값을 0으로 설정하게 되면 테이블 row가 몇건이든 간에 사용자가 지정한
autovacuum_vacuum_threshold 의 설정값을 기준으로 Dummy Data(Dead Tuple)를 Autovacuum이 정리하게 됩니다. Autovacuum은 운영중인 데이터베이스에서 수행되어도 문제가 없기 때문에 일반적으로 Autovacuum을 설정하여 주기적으로 Dummy Data(Dead Tuple)을 재사용 가능한 상태로 만들어 최적의 디스크 공간 유지를 하게끔 합니다.
Dummy Data(Dead Tuple) 조회 방법 참고
-- Dead Tuple 10,000 이상인 테이블 목록 조회
SELECT
n.nspname AS schema_name,
c.relname AS table_name,
pg_stat_get_live_tuples(c.oid) + pg_stat_get_dead_tuples(c.oid) as total_tuple,
pg_stat_get_live_tuples(c.oid) AS live_tuple,
pg_stat_get_dead_tuples(c.oid) AS dead_tupple,
round(100*pg_stat_get_live_tuples(c.oid) / (pg_stat_get_live_tuples(c.oid) + pg_stat_get_dead_tuples(c.oid)),2) as live_tuple_rate,
round(100*pg_stat_get_dead_tuples(c.oid) / (pg_stat_get_live_tuples(c.oid) + pg_stat_get_dead_tuples(c.oid)),2) as dead_tuple_rate,
pg_size_pretty(pg_total_relation_size(c.oid)) as total_relation_size,
pg_size_pretty(pg_relation_size(c.oid)) as relation_size
FROM pg_class AS c
JOIN pg_catalog.pg_namespace AS n
ON n.oid = c.relnamespace
WHERE
pg_stat_get_live_tuples(c.oid) > 0
AND c.relname NOT LIKE 'pg_%'
AND pg_stat_get_dead_tuples(c.oid) >= 10000
ORDER BY dead_tupple DESC;
참조 사이트
DB 인사이드 | PostgreSQL Vacuum - 1. MVCC
📢 Vacuum Series의 첫 시작으로, PostgreSQL의 MVCC모델에 대해 알아보도록 하겠습니다. 본 문서에서는 ①MVCC동작 방식 및 예제를 설명한 후 ②해당 모델로 인해 발생 가능한 문제점들을 알아보도록 하
blog.ex-em.com
'PostgreSQL > Architecture' 카테고리의 다른 글
[PostgreSQL] SQL 처리 과정 (6) (2) | 2023.11.29 |
---|---|
[PostgreSQL] 동작 원리 (5) (2) | 2023.11.28 |
[PostgreSQL] Memory 구조 (4) (0) | 2023.11.28 |
[PostgreSQL] Process 구조 (3) (0) | 2023.11.28 |
[PostgreSQL] Data Directory 구조 (2) (0) | 2023.11.28 |