본문으로 건너뛰기
김신건의 로그

External Merge Sort

· 수정 · 📖 약 3분 · 1,005자/단어 #algorithm #sorting #database #external-sort #spill
external merge sort, 외부 정렬, 외부 머지 정렬, External Sort

정의

External Merge Sort (외부 머지 정렬) 는 데이터가 메모리에 들어가지 않을 때 사용하는 Merge Sort 변형. 두 단계로 동작한다.

  1. Run 생성: 메모리 크기만큼 청크를 잘라 메모리 내에서 정렬한 뒤 디스크에 “Run” 파일로 저장
  2. K-way Merge: 모든 Run 의 head 버퍼만 메모리에 두고 한 번에 합쳐 정렬된 출력 생성

RDBMS 가 ORDER BY, GROUP BY, DISTINCT, UNION 을 처리할 때의 주력 알고리즘. 자세한 메커니즘과 Oracle/PostgreSQL/SQL Server 의 구현 차이는 정렬·해시는 메모리가 부족하면 어디로 새는가, PGA, work_mem, Workspace Memory 글 참고.

시각화

알고리즘

externalMergeSort(input, M):  // M = 가용 메모리
  // 1단계: Run 생성
  runs = []
  while input has data:
    chunk = read M bytes from input
    sort chunk in memory (예: Quicksort)
    write chunk to disk as a new Run
    runs.append(Run path)

  // 2단계: K-way Merge
  open all runs as input streams
  initialize priority queue with first element of each run
  while priority queue not empty:
    min = pop smallest from priority queue
    write min to output
    if min's run has more data:
      push next element from that run

  return output

1단계: Run 생성 (Run Generation)

각 청크를 메모리에서 정렬 후 디스크에 저장. 메모리는 다음 청크를 위해 재사용.

[데이터 1GB] / [메모리 256MB]
→ 4 개 청크
→ 4 개 정렬된 Run 파일 생성
→ 각 Run 은 메모리 크기 (256MB)

청크 내부 정렬에는 보통 Quicksort 를 쓴다 (in-memory 에서 가장 빠름).

2단계: K-way Merge

K 개의 정렬된 Run 을 동시에 머지. 각 Run 의 head 버퍼만 메모리에 둔다, 데이터 전체가 아니라.

Run 1: [1, 4, 9, 11, ...]     head = 1
Run 2: [2, 5, 7, 13, ...]     head = 2
Run 3: [3, 6, 8, 10, ...]     head = 3
Run 4: [0, 12, 14, 15, ...]   head = 0

다음 출력 = 가장 작은 head = 0 (Run 4 에서)
→ Run 4 의 다음 값 가져옴
→ 다시 가장 작은 head 선택 → ...

priority queue (min-heap) 로 K 개 중 최솟값을 O(log K) 에 찾는다.

복잡도

항목설명
CPU 시간O(n log n)Run 정렬 + Merge
디스크 I/O2 × n (1-pass)Run 쓰기 1번 + 머지 읽기 1번
메모리√(D × P)D = 데이터 크기, P = 페이지 크기
안정성✓ (구현에 따라)Merge 단계가 안정적이라면

메모리 요구량의 우아한 성질

가용 메모리 M, 데이터 D, 페이지 크기 P 일 때 K-way merge 의 메모리:

K = D / M  (Run 수)
머지 메모리 = (K + 1) × P
           = (D / M) × P
           = D × P / M

One-pass 조건: D × P / M ≤ M
            → M ≥ √(D × P)

IMPORTANT

K-way Merge 의 메모리는 데이터 크기에 비례하지 않는다. 데이터 크기 D, 페이지 크기 P 일 때 √(D × P) 에 비례한다. 그래서 한 자릿수 GB 의 정렬도 수십 MB 로 충분히 처리된다. 외부 머지 정렬의 가장 우아한 성질.

예시 (Oracle 공식 문서):

  • 1 GB 정렬 + 8 KB 페이지 → 최소 √(1 GB × 8 KB) ≈ 2.8 MB
  • 보수적으로 22 MB 로 1-pass 가능 (overhead 포함)

3 단계 모드

데이터 크기와 메모리 비율에 따라.

모드조건디스크 I/O응답 시간
OptimalM ≥ D0빠름 (in-memory Quicksort)
One-pass√(D × P) ≤ M < D2 × D보통
Multi-passM < √(D × P)K × 2 × DK 배 느려짐 (지수적)

CAUTION

Multi-pass 진입 시 K=2 만 돼도 디스크 I/O 가 4 배, K=3 이면 6 배. 응답 시간이 메모리 부족량에 대해 거의 지수적으로 증가.

RDBMS 구현 비교

DBMS메모리 영역디스크 위치조절
OraclePGA → Sort Area (work area)TEMP tablespace (sort segment 자동)PGA_AGGREGATE_TARGET
PostgreSQLwork_membase/pgsql_tmp/SET work_mem (세션별)
SQL ServerWorkspace Memory / Memory Granttempdb (Worktable / Workfile)Resource Governor + Memory Grant Feedback

자세한 구현 디테일은 정렬·해시는 메모리가 부족하면 어디로 새는가, PGA, work_mem, Workspace Memory 참고.

모니터링 지표

Oracle

SELECT operation_type, work_area_size, expected_size,
       last_memory_used, last_execution
FROM v$workarea_active;
-- last_execution: OPTIMAL / ONE PASS / MULTI-PASSES

PostgreSQL

EXPLAIN ANALYZE SELECT * FROM big_table ORDER BY col;
-- "Sort Method: quicksort  Memory: 25kB"        ← Optimal
-- "Sort Method: external merge  Disk: 17904kB"  ← Spill 발생

SQL Server

SELECT requested_memory_kb, granted_memory_kb, used_memory_kb,
       ideal_memory_kb, dop
FROM sys.dm_exec_query_memory_grants;
-- granted < ideal: Memory Grant 부족 = Spill 위험

함정

1. work_mem 을 크게 잡으면 안전한가?

SET work_mem = '256MB';  -- 위험

PostgreSQL 의 work_mem세션당, 연산자당 적용. 동시 접속 100 × 노드 4 × parallel 4 = 400 GB 까지 갈 수 있다. OOM 직행.

2. Run 수가 너무 많으면

K 가 커지면 priority queue 의 O(log K) 가 무시 못할 비용. K=1000 이면 비교당 10 회 비교. 보통 DBMS 가 자동으로 다중 패스로 전환.

3. 입력이 이미 정렬됨

PostgreSQL 은 sort 노드가 이미 정렬된 입력을 감지하면 skip. Oracle 은 인덱스 기반 ORDER BY 가 정렬을 회피.

역사

  • 1945: John von Neumann 이 Merge Sort 발명
  • 1950s-60s: 자기 테이프 시대에 외부 머지 정렬이 사실상 유일한 정렬 방법
  • 1970s: 디스크 시대, K-way merge 의 메모리 최적화 활발
  • 현재: 클라우드 DW (BigQuery, Snowflake, Spark) 도 같은 패턴. 다만 디스크 대신 분산 노드로 확장

참고

이 글의 용어 (3개)
정렬 알고리즘algorithm
정의 정렬 (sort) 은 원소들의 컬렉션을 어떤 전순서 (total order) 기준으로 재배열하는 것. 알고리즘 입문의 정석 주제이자, 데이터베이스·검색·통계 등 모든 시스템…
Merge Sortalgorithm
정의 Merge Sort (병합 정렬) 는 분할 정복 (Divide & Conquer) 으로 동작하는 비교 정렬. 배열을 반으로 나눠 각각 정렬한 뒤, 두 정렬된 부분을 병합 (…
Quick Sortalgorithm
정의 Quick Sort (퀵 정렬) 는 분할 정복 (Divide & Conquer) 기반 비교 정렬. 1959 년 Tony Hoare 가 고안. 배열에서 pivot 을 하나 골…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기