PostgreSQL에서 VACUUM: 개념, 중요성

이세현·2024년 9월 5일
0

PostgreSQL for DBA

목록 보기
9/19

PostgreSQL에서 VACUUM: 개념, 중요성

PostgreSQL는 오랜 기간 동안 신뢰성과 성능으로 많은 개발자와 기업들 사이에서 널리 사용되고 있는 데이터베이스 관리 시스템(DBMS)입니다. 특히 트랜잭션 처리에서 강력한 기능을 제공하는데, 이는 여러 사용자가 동시에 데이터베이스에 접근하고 수정하는 상황에서 매우 중요합니다.

하지만 이와 같은 트랜잭션 처리로 인해 시간이 지남에 따라 데이터베이스에 불필요한 데이터가 쌓이고, 성능 저하가 발생할 수 있습니다. 이를 해결하기 위한 주요 도구 중 하나가 바로 VACUUM입니다. 이 블로그에서는 VACUUM의 기본 개념, 왜 필요한지, 그리고 이를 최적화하는 방법에 대해 깊이 있게 다뤄보겠습니다.

다음 블로그엔 pg_squeeze이용하여 Vacuum 최적화 진행할 것입니다.

1. VACUUM이란 무엇인가?

PostgreSQL에서 VACUUM은 삭제되거나 업데이트된 행들(레코드)을 정리하는 작업을 의미합니다. 트랜잭션 처리 중 발생하는 죽은 튜플(dead tuples)을 제거하여 데이터베이스 파일의 공간을 회수하고 성능을 유지하는 데 필수적인 역할을 합니다.

VACUUM은 일반적으로 데이터베이스의 테이블에서 삭제되거나 무효화된 레코드들을 제거하고, 그 공간을 다시 사용할 수 있도록 관리합니다.

트랜잭션과 VACUUM의 관계

PostgreSQL은 MVCC(Multi-Version Concurrency Control) 방식을 사용하여 트랜잭션 간의 동시성을 보장합니다. 트랜잭션이 진행되면서 새로운 행이 삽입되거나 기존 행이 삭제, 수정되면 실제로 데이터를 즉시 삭제하거나 수정하지 않고, 새로운 버전을 생성합니다.

이러한 방식 덕분에 여러 트랜잭션이 동시에 동일한 데이터를 접근하더라도 충돌 없이 작업을 수행할 수 있습니다.

예를 들어, 두 개의 트랜잭션이 동시에 동일한 테이블에 접근하고 각각 데이터를 처리한다고 가정해보겠습니다.

Transaction 1Transaction 2
SELECT count(*) FROM tab;SELECT count(*) FROM tab;
... 반환: 0 ...... 반환: 0 ...
BEGIN;
INSERT INTO tab VALUES (1, 2, 3);
SELECT count(*) FROM tab;SELECT count(*) FROM tab;
... 반환: 3 ...... 반환: 0 ...
ROLLBACK; <-- 3개의 행은 삭제됨

위의 예시에서, 중요하게 이해해야 할 점은 두 세션에서 서로 다른 데이터를 볼 수 있다는 것입니다. 왼쪽 세션은 실제로 3개의 행을 보겠지만, 동시에 실행되는 오른쪽 세션에서는 해당 트랜잭션이 아직 커밋되지 않았기 때문에 어떤 행도 보지 못합니다.

ROLLBACK의 대상이 된 3개의 행을 어떻게 제거할 수 있을까요? MSSQL과 Oracle과는 달리, PostgreSQL에서는 ROLLBACK 시 디스크에서 이러한 행을 제거하지 않으므로 PostgreSQL에서 ROLLBACK이 매우 빠르고, MSSQL에서 큰 트랜잭션의 경우 매우 느린 이유입니다.

이때, Vacuum의 역할은 더 이상 어떤 활성 트랜잭션에서도 볼 수 없는 행들을 제거하는 것입니다.

주요 포인트

  • 긴 트랜잭션은 VACUUM의 동작을 지연시킴.
  • VACUUM이 실행되더라도 아직 볼 수 있는 데이터는 삭제되지 않음.
  • VACUUM의 효과를 보기 위해서는 트랜잭션을 신속하게 종료하는 것이 중요함.

2. 왜 VACUUM은 디스크 공간을 바로 반환하지 않는가?

많은 PostgreSQL 사용자들이 종종 질문하는 내용 중 하나는, 왜 VACUUM을 실행했는데도 디스크 공간이 줄어들지 않나요? 입니다. 이는 PostgreSQL의 내부 구조와 VACUUM 작업이 어떻게 수행되는지에 대한 이해가 필요합니다.

VACUUM은 삭제된 행을 디스크에서 물리적으로 제거하지 않고, 단순히 "죽은 튜플"로 마킹하고, 이후 삽입되는 데이터가 이 공간을 재사용하도록 설계되어 있습니다. 이를 통해 디스크에서 데이터를 물리적으로 이동시키는 작업을 줄이고, 성능을 유지할 수 있습니다.

간단한 테이블을 생성하고 VACUUM이 어떻게 동작하는지 살펴보는 예시를 통해서 Vacuum이 공간을 관리를 어떻게 하는지 보겠습니다.

/*
이 테이블에 데이터를 삽입하고 각 행이 어느 블록에 저장되었는지 확인
각 행은 ctid를 통해 데이터가 저장된 블록을 확인할 수 있으며, VACUUM 실행 전후의 블록 상태를 관찰할 수 있습니다. 
pg_freespacemap 확장을 사용하면 각 블록의 남은 공간을 보기 가능*/


postgres=# CREATE TABLE t_vacuum (
          id    int,
          x     char(1500) DEFAULT 'pglover'
);
CREATE TABLE
postgres=# INSERT INTO t_vacuum
     SELECT id FROM generate_series(1, 300) AS id;
INSERT 0 300

postgres=# SELECT ctid, id FROM t_vacuum limit 20;
 ctid  | id
-------+----
 (0,1) |  1
 (0,2) |  2
 (0,3) |  3
 (0,4) |  4
 (0,5) |  5
 (1,1) |  6
 (1,2) |  7
 (1,3) |  8
 (1,4) |  9
 (1,5) | 10
 (2,1) | 11
 (2,2) | 12
 (2,3) | 13
 (2,4) | 14
 (2,5) | 15
 (3,1) | 16
 (3,2) | 17
 (3,3) | 18
 (3,4) | 19
 (3,5) | 20
(20 rows)

PostgreSQL에서 1,500바이트가 넘는 300개의 큰 행이 있는 테이블을 생성하면, 8k 블록에 5개의 행만 저장됩니다. 각 행이 어느 블록에 있는지 확인하기 위해 숨겨진 열 "ctid"를 사용할 수 있습니다. 예를 들어, ctid = '(2, 4)'는 두 번째 블록의 네 번째 행을 의미합니다.

행을 삭제하고 VACUUM을 실행하면 어떤 일이 일어나는지 확인하기 위해, 테이블 내부의 변화를 살펴보기 위한 확장 기능을 활성화할 수 있습니다.

삭제 작업 후 VACUUM을 실행하면, 공간이 회수되어 향후 데이터 삽입 시 재사용될 수 있는 것을 확인할 수 있습니다. 하지만 이 과정에서 디스크 자체의 공간이 줄어드는 것은 아닙니다. VACUUM이 테이블 간 데이터 이동을 수행하지 않기 때문입니다.


pg_fresspace extension설치

pg_freespacemap 확장은 PostgreSQL에서 자유 공간 맵(FSM, Free Space Map) 정보를 조회할 수 있게 해주는 도구입니다. 이 맵은 PostgreSQL이 각 테이블의 페이지에서 얼마나 많은 여유 공간이 있는지를 추적하는 데 사용됩니다. 이러한 정보를 통해 쓸 수 있는 빈 공간을 찾아서 데이터가 효율적으로 저장될 수 있도록 도와줍니다.

주요 기능

  • 공간 관리: pg_freespacemap은 PostgreSQL 테이블 페이지의 여유 공간을 추적하는 메커니즘입니다. 테이블에 데이터를 삽입할 때, 이미 할당된 페이지에서 빈 공간을 찾아 데이터를 추가하는 방식으로 사용됩니다.
  • 성능 최적화: 여유 공간이 있는 페이지를 효율적으로 사용하면 새로운 페이지를 할당하지 않아도 되기 때문에 성능이 개선될 수 있습니다.
  • VACUUM과 연계: VACUUM 작업은 삭제된 데이터가 있는 공간을 해제하고, 이 해제된 공간을 추적하는 데 자유 공간 맵을 사용합니다. 이로써 PostgreSQL이 효율적으로 디스크 공간을 재사용할 수 있게 합니다
sudo yum install postgresql16-contrib
sudo systemctl restart postgresql-16

postgres=# CREATE EXTENSION pg_freespacemap;
CREATE EXTENSION
postgres=# SELECT * FROM pg_freespace('t_vacuum');
 blkno | avail
-------+-------
     0 |   448
     1 |   448
     2 |   448
     3 |   448
     4 |   448
     5 |   448
     6 |   448
     7 |   448
     8 |   448
     9 |   448
    10 |   448
    11 |   448
'''
중략
'''

    59 |     0
(60 rows)


1. 데이터를 삭제하고 상황을 확인

postgres=# DELETE FROM t_vacuum
           WHERE  id = 7 OR id = 8
           RETURNING ctid;
 ctid
-------
 (1,2)
 (1,3)
(2 rows)

2. 데이터 파일에 갭이 생긴

DELETE 2
postgres=# SELECT       ctid, id
        FROM    t_vacuum
        WHERE   id BETWEEN 5 AND 10;
 ctid  | id
-------+----
 (0,5) |  5
 (1,1) |  6
 (1,4) |  9
 (1,5) | 10
(4 rows)

3. ctid 값이 (1,2)와 (1,3)인 행이 삭제되었으며, 이 행들은 이제 "죽은" 상태로 표시됩니다. 데이터는 실제로는 디스크에서 죽어 있지만, freespace map(자유 공간 맵)을 확인해 보면 내용이 변하지 않았습니다

postgres=# select * from pg_freespace('t_vacuum');
 blkno | avail
-------+-------
     0 |   448
     1 |  448
     2 |   448
     3 |   448
     4 |   448
     5 |   448
     6 |   448
     7 |   448
     8 |   448
     9 |   448
    10 |   448
    11 |   448
'''
중략
'''

    59 |     0
(60 rows)

중요한 점은 데이터가 삭제되더라도 공간이 즉시 회수되지 않는다는 것입니다. 공간은 VACUUM 명령어를 통해 회수

4. vacuum 회수

postgres=# VACUUM t_vacuum;
VACUUM

5. VACUUM 명령어가 실행된 후(긴 실행 트랜잭션이 작업을 방해하지 않는 경우), freespace map(FSM)은 디스크의 새로운 현실을 반영

postgres=# SELECT * FROM pg_freespace('t_vacuum');
 blkno | avail 
-------+-------
     0 |   448
     1 |  3520
     2 |   448
     3 |   448
     4 |   448
     5 |   448
 	6 |   448
     7 |   448
     8 |   448
     9 |   448
    10 |   448
    11 |   448
'''
중략
'''

    59 |     448
(60 rows)

Point1

여전히 60개의 블록이 있지만, 이제 두 번째 블록에 훨씬 더 많은 여유 공간이 있습니다. 일반적인 VACUUM은 블록 간에 데이터를 이동하지 않으며, 이는 기본 동작 방식입니다. 따라서 공간은 파일 시스템으로 반환되지 않습니다. 그러나 대부분의 경우 나중에 사용할 수 있기 때문에 큰 문제는 없습니다.

Point2

이와 같이 VACUUM은 공간을 다시 사용할 수 있도록 블록 내에 여유 공간을 확보하지만, 디스크 공간을 즉시 반환하지는 않습니다. VACUUM FULL을 실행해야만 물리적으로 공간을 반환할 수 있지만, 이 작업은 성능 저하를 유발할 수 있습니다.

결론

VACUUM은 PostgreSQL 데이터베이스에서 공간을 효율적으로 관리하고 성능을 유지하는 데 중요한 역할을 합니다. 그러나 VACUUM이 디스크 공간을 즉시 반환하지 않는 이유와 VACUUM FULL의 필요성에 대한 이해는 중요합니다. 일반적인 VACUUM은 공간을 재사용할 수 있도록 하지만, 디스크에서 물리적으로 공간을 반환하기 위해서는 VACUUM FULL과 같은 추가 작업이 필요합니다. 이를 통해 데이터베이스의 성능을 최적화하고, 데이터의 효율적인 저장과 관리를 할 수 있습니다.

Reference

https://www.cybertec-postgresql.com/en/vacuum-managing-and-detecting-bloat/

profile
pglover_12

0개의 댓글