ONE QUESTION AT A TIME.

천천히 생각하고, 분명하게.

TODAY’S QUESTION1435 / 1500

PostgreSQL 행의 큰 text/json 값을 TOAST가 inline 대신 외부에 저장하는 이유와 조회 비용은 무엇인가요?

잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?

답변과 점검 포인트 펼치기답변 접기
01

구두 답변

정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.

결론부터 말하면 TOAST는 큰 값을 무조건 별도 테이블로 옮기는 기능이 아니라, 하나의 heap tuple이 고정된 page를 넘을 수 없다는 제약을 만족시키는 저장 경로입니다. PostgreSQL은 저장 전략에 따라 attribute를 먼저 압축하고, 그래도 tuple이 크면 TOAST relation의 chunk로 외부화합니다. heap에는 큰 값 전체가 아니라 이를 해석할 pointer 표현이 남을 수 있습니다. 압축 결과가 page에 들어가면 inline에 남을 수도 있으므로 “1MB면 항상 외부 저장”이라고 말하지 않습니다.

id=42, status, payload=1MB인 행을 두 질의로 나누면 비용 경계가 보입니다. SELECT id,status WHERE id=42는 id 인덱스로 TID를 얻은 뒤 heap에서 작은 컬럼만 확인하는 경로라 payload chunk를 읽지 않을 수 있습니다. 반면 SELECT payload ...는 반환을 위해 datum을 재구성하고, payload LIKE '%error%'나 length(payload)>100은 SELECT 목록에 없더라도 조건 평가 때문에 값을 열 수 있습니다. 예시 trace는 index lookup → heap tuple → TOAST pointer → chunk fetch/decompress → expression 순서입니다. 실제 fetch 여부는 plan과 함수, 캐시, 저장 상태로 검증해야 하며 인덱스가 행을 찾았다는 사실만으로 큰 값 비용이 사라지지 않습니다.

조회 경로를 판단할 때는 행을 찾는 비용과 datum을 소비하는 비용을 계측 포인트로 나눕니다. 동일한 id=42에 대해 작은 컬럼만 반환하는 실행, payload를 반환하는 실행, payload 내부 조건을 평가하는 실행을 각각 warm cache와 cold cache에서 비교하면 TOAST pointer 자체의 비용과 chunk read·decompression 비용을 구별할 수 있습니다. 이 구분이 있어야 “TOAST를 피하자”가 아니라 어떤 query shape에서 projection·expression index·컬럼 분리를 적용할지 결정할 수 있습니다.

02

득점 포인트

이해가 드러나는 지점을 확인해 보세요.

  • tuple/page 한계를 먼저 말하고 압축, pointer, out-of-line chunk 순서를 연결합니다.
  • SELECT id,status와 payload LIKE에서 필요한 물리 경로가 다름을 설명합니다.
  • 1MB라는 논리 크기를 threshold의 보편 숫자로 사용하지 않고 저장 전략·압축률을 조건으로 둡니다.
03

감점 포인트

놓치기 쉬운 조건과 오해를 짚어 보세요.

  • 큰 값은 언제나 별도 일반 테이블에 저장된다고 단정합니다.
  • SELECT 목록에 payload가 없으면 predicate나 함수에서도 절대 fetch가 없다고 말합니다.
  • 인덱스 lookup 비용과 TOAST datum materialization 비용을 하나의 숫자로 합칩니다.
04

더 파고들 거리

하나 더 질문하며 이해의 범위를 넓혀 보세요.

  • 특정 버전에서 EXTERNAL, EXTENDED, MAIN, PLAIN이 압축·외부화에 미치는 범위를 확인해 보세요.
  • EXPLAIN (ANALYZE, BUFFERS)와 relation-level I/O로 heap read와 large datum read를 어떻게 분리할지 설계해 보세요.

득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.

← 전체 질문 보기