4.5 디스크 레이아웃과 tablespace
PostgreSQL의 모든 데이터는 기본적으로 PGDATA 한 디렉토리에 저장된다(1.5 참고). 하지만 운영 환경에서는 테이블·인덱스·WAL을 다른 디스크에 분산하고 싶은 경우가 흔하다 — 빠른 NVMe와 큰 HDD를 함께 쓰거나, WAL을 별도 디스크로 떼서 commit latency를 줄이거나, hot table을 더 빠른 볼륨에 두거나. 이를 위한 메커니즘이 tablespace다.
tablespace란
tablespace는 이름 + 디스크 경로의 쌍입니다. 테이블·인덱스를 만들 때 어떤 tablespace에 둘지 지정하면, 그 객체의 파일이 해당 경로 아래에 들어갑니다.
-- 1. tablespace 생성 (postgres 사용자가 쓰기 권한을 가진 빈 디렉토리 필요)
CREATE TABLESPACE fast_ssd LOCATION '/mnt/nvme0/pgdata';
-- 2. 테이블을 그 tablespace에 생성
CREATE TABLE hot_orders (...) TABLESPACE fast_ssd;
-- 3. 기존 테이블 이동
ALTER TABLE accounts SET TABLESPACE fast_ssd;이동(ALTER TABLE SET TABLESPACE)은 ACCESS EXCLUSIVE 락을 잡으므로 대용량 테이블은 운영 시간 외에 실행합니다. PG 12+의 CREATE INDEX CONCURRENTLY ... TABLESPACE는 인덱스를 무중단으로 다른 tablespace에 만들 수 있습니다.
디스크 구조
tablespace를 만들면 PGDATA에는 심볼릭 링크만 들어가고, 실제 데이터는 외부 경로에 저장됩니다.
$PGDATA/
└── pg_tblspc/
└── 16400 -> /mnt/nvme0/pgdata # 심볼릭 링크
/mnt/nvme0/pgdata/
└── PG_17_202402051/ # 메이저 버전 + catalog version
└── 16384/ # 데이터베이스 OID
├── 16401 # relfilenode (테이블 파일)
├── 16401_fsm
└── 16401_vmPG_<ver>_<catversion> 디렉토리가 한 단계 더 들어가는 이유: 메이저 업그레이드(pg_upgrade) 시 옛 클러스터와 새 클러스터가 같은 디스크를 공유해도 충돌하지 않도록 격리하기 위해서.
기본 tablespace 두 개
initdb 직후 클러스터는 두 개의 logical tablespace를 갖습니다.
| tablespace | 위치 | 용도 |
|---|---|---|
pg_default | $PGDATA/base/ | 사용자 객체 기본 |
pg_global | $PGDATA/global/ | 클러스터 전역 카탈로그 (pg_database, pg_authid 등). 이동 불가 |
이 둘은 일반 tablespace처럼 다루지만 PGDATA 안에 위치합니다.
분리 패턴
WAL 분리
가장 흔한 패턴입니다. WAL은 순차 쓰기·짧은 latency가 핵심이라 별도 빠른 디스크에 두면 commit이 빨라집니다.
WAL은 tablespace로 분리하지 않고, PGDATA를 초기화할 때 --waldir 옵션 또는 pg_wal/을 심볼릭 링크로 만듭니다.
# initdb 시
initdb -D /var/lib/pgsql/17/data \
--waldir=/mnt/wal_nvme/17/pg_wal \
--data-checksums
# 또는 기존 클러스터에서 — 클러스터 중지 후
pg_ctl stop -D /var/lib/pgsql/17/data
mv $PGDATA/pg_wal /mnt/wal_nvme/pg_wal
ln -s /mnt/wal_nvme/pg_wal $PGDATA/pg_wal
pg_ctl start -D /var/lib/pgsql/17/dataHot 테이블만 NVMe로
큰 테이블 중 hot 일부만 빠른 디스크에.
CREATE TABLESPACE nvme LOCATION '/mnt/nvme/pgdata';
ALTER TABLE orders SET TABLESPACE nvme;
ALTER TABLE order_items SET TABLESPACE nvme;
-- 인덱스도 같이
ALTER INDEX orders_pkey SET TABLESPACE nvme;데이터·인덱스를 같이 옮겨야 효과적. 인덱스만 빠른 디스크에 두는 패턴은 옛날 HDD 시절의 흔적이지, 요즘은 함께 옮기는 게 보통입니다.
temp 파일 분리
정렬·해시 spill·임시 테이블이 쓰는 임시 파일을 별도 디스크에.
CREATE TABLESPACE temp_ssd LOCATION '/mnt/temp_nvme/pgdata';temp_tablespaces 파라미터로 활용:
ALTER SYSTEM SET temp_tablespaces = 'temp_ssd';
SELECT pg_reload_conf();여러 tablespace를 ,로 나열하면 round-robin으로 분산. 대용량 ETL·warehouse 워크로드에 효과적.
비용·트레이드오프
tablespace는 만능 도구가 아닙니다. 분리해서 얻는 이득과 복잡도를 저울질해야 합니다.
| 이점 | 비용 |
|---|---|
| 빠른 디스크에 hot 데이터 집중 | 두 디스크 모두 백업·모니터링·여유 공간 관리 필요 |
| WAL 분리로 commit latency 개선 | 디스크 1개 장애가 클러스터 정지 (WAL 손실은 곧 데이터 손실) |
| temp 파일 분리로 OLTP 안정 | tablespace 디렉토리가 사라지면 클러스터 부팅 실패 |
| 백업·복제 도구가 잘 지원하는지 확인 필요 | pgBackRest, Barman은 OK. 일부 자체 스크립트는 tablespace 미지원 |
백업과의 상호작용
pg_basebackup·pgBackRest·Barman 모두 tablespace를 인식해 같이 백업합니다. pg_dump는 tablespace 정의도 dump에 포함 (단, --no-tablespaces로 빼면 복원 시 무시).
복원 시 같은 tablespace 경로가 있어야 한다 — 다른 호스트로 복원하면 마운트 포인트가 같지 않을 가능성이 높아 tablespace_map을 직접 편집하는 패턴이 흔하다 (Part XI 백업 참고).
tablespace의 객체 확인
-- 정의 목록
SELECT spcname, pg_tablespace_location(oid) AS location
FROM pg_tablespace;
-- 어느 테이블이 어느 tablespace에 있나
SELECT n.nspname, c.relname, t.spcname AS tablespace
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
LEFT JOIN pg_tablespace t ON c.reltablespace = t.oid
WHERE c.relkind IN ('r','i')
ORDER BY tablespace, c.relname
LIMIT 20;
-- 데이터베이스의 기본 tablespace
SELECT datname, t.spcname
FROM pg_database d
JOIN pg_tablespace t ON d.dattablespace = t.oid;디스크 레이아웃 의사결정 체크리스트
| 시나리오 | 권장 |
|---|---|
| 클라우드 단일 볼륨 (EBS 등) | 분리할 가치 적음 — 단일 디스크 |
| 베어메탈, NVMe + SATA 혼합 | WAL은 NVMe, 데이터는 SATA + hot table은 NVMe |
| 워크로드가 단순 OLTP | 분리하지 말고 단일 PGDATA가 운영·백업 가장 간단 |
| 대용량 분석 + OLTP 혼재 | temp_tablespaces로 분석용 임시 분리 |
| 메이저 업그레이드 계획 | pg_upgrade --link가 tablespace를 잘 다루지만 디스크 마운트 경로가 그대로여야 |
ALTER TABLESPACE ... SET (TABLESPACE = …)) 또는 클러스터 중지 후 심볼릭 링크 재작성합니다.정리
- tablespace = 이름 + 외부 디렉토리. 테이블·인덱스를 다른 디스크에 둘 수 있게 함
- 기본 두 개:
pg_default(사용자 데이터),pg_global(전역 카탈로그, 이동 불가) - WAL 분리는
--waldir또는pg_wal심볼릭 링크 - temp 파일 분리는
temp_tablespaces파라미터 + 전용 tablespace - 모든 tablespace는 백업·복제·디스크 장애 관리에 포함시켜야 함
- 클라우드 단일 볼륨 환경에서는 분리할 가치 적음
Part IV 스토리지와 I/O가 끝났습니다. 다음 Part V에서는 SQL이 실제로 어떻게 실행되는지 — 쿼리 처리의 단계를 봅니다.