SQLite 스토리지 심층 분석

발행: (2026년 1월 15일 오전 03:48 GMT+9)
12 min read
원문: Dev.to

Source: Dev.to

Hello, I’m Maneshwar. I’m working on FreeDevTools online – a free, open‑source hub that gathers all dev tools, cheat codes, and TL;DRs in one place so developers don’t have to hunt across the web.

어제 우리는 Page 1, 모든 SQLite 데이터베이스 파일의 변하지 않는 시작 지점을 살펴보았습니다.
오늘은 SQL 레이어에서는 보이지 않지만 SQLite의 공간 관리, 충돌 복구, 그리고 장기 성능에 필수적인 파일 내부 요소들로 더 깊이 들어갑니다.

이 글은 freelists, leaf pages, trunk pages, 그리고 마지막으로 journals – SQLite의 안전망 – 에 대해 설명하면서 여정을 이어갑니다.

SQLite가 프리리스트가 필요한 이유

  • SQLite는 사용되지 않은 페이지를 즉시 운영 체제에 반환하지 않습니다.
  • 페이지가 할당되면 명시적인 축소 작업이 발생할 때까지 파일에 그대로 남아 있습니다.
  • 행이 삭제되거나, 인덱스가 제거되거나, 테이블이 삭제될 때 해당 페이지들은 비활성이 됩니다.

SQLite는 이러한 페이지들을 버리는 대신 프리리스트(freelist)라고 하는 구조에 넣습니다 – 이는 파일을 확장하지 않고도 향후 삽입 작업에 재사용할 수 있는 사용되지 않은 페이지들의 내부 목록입니다.

프리리스트란?

프리리스트는 데이터베이스 파일 내부에 직접 삽입된 연결 구조입니다.

Freelist diagram

핵심 사실

Offset의미
32첫 번째 프리리스트 트렁크 페이지 번호 (파일 헤더에 저장)
36전체 자유 페이지 수

모든 자유 페이지가 추적되며, 가비지 컬렉션이나 모호함이 없습니다. SQLite는 프리리스트를 루트 트리와 같은 리스트로 조직하여 파일 헤더에서 시작해 외부로 분기합니다.

트렁크 페이지와 리프 페이지 (프리리스트 페이지)

Freelist 페이지는 두 가지 하위 유형으로 구성됩니다.

트렁크 페이지

트렁크 페이지는 자유 페이지들의 디렉터리 역할을 합니다. 그 레이아웃은 (페이지 시작부터) 다음과 같습니다:

바이트내용
4다음 트렁크 페이지의 페이지 번호 (없으면 0)
4이 트렁크에 저장된 리프 포인터 수
N × 4리프 페이지들의 페이지 번호

각 트렁크 페이지는 한 번에 많은 자유 페이지들을 참조할 수 있습니다.

리프 페이지

리프 페이지는 의미 있는 구조가 없는 자유 페이지입니다. 내용은 지정되지 않았으며 이전 사용에서 남은 데이터가 포함될 수 있습니다. 리프 페이지가 실제 재사용 가능한 페이지이며, 트렁크 페이지는 단지 그들을 가리키는 역할을 합니다.

페이지가 프리리스트에 들어가고 나가는 방법

  • 페이지가 비활성화되면 SQLite 프리리스트에 추가합니다. 해당 페이지는 파일 안에 물리적으로 남아 있습니다.
  • 새 데이터를 기록해야 할 때, SQLite는 프리리스트에서 페이지를 가져옵니다.

Freelist usage diagram

이는 SQLite 데이터베이스가 종종 크기는 커지지만 자동으로 줄어들지는 않는 이유를 설명합니다.

데이터베이스 축소: VACUUM 및 Autovacuum

프리리스트가 너무 커지면 디스크 사용량이 낭비됩니다. SQLite는 두 가지 해결책을 제공합니다.

VACUUM

VACUUM diagram

VACUUM 은 무겁지만 정확한 작업으로, 사용되지 않은 페이지를 버리고 전체 데이터베이스 파일을 다시 구축합니다.

Autovacuum 모드

Autovacuum diagram

Autovacuum 은 작은 실행 시간 오버헤드를 감수하고 지속적인 공간 정리를 수행합니다. 사용 가능한 페이지가 생길 때마다 자동으로 파일 끝으로 이동시켜 공간을 정리합니다.

SQLite의 저널 파일

저널은 데이터베이스 변경 사항을 기록하는 충돌 복구 파일로, SQLite가 불완전한 트랜잭션을 롤백할 수 있게 합니다. 이는 원자성지속성을 보장하여, 장애 발생 후 데이터베이스가 절반만 기록된 상태로 남지 않도록 합니다.

SQLite는 전통적으로 레거시 저널링을 사용했으며, 여기에는 다음이 포함됩니다:

  • 롤백 저널
  • 스테이트먼트 저널
  • 마스터 저널

SQLite 3.7.0부터는 데이터베이스가 레거시 저널링 또는 WAL 중 하나만 사용하며, 두 방식을 동시에 사용하지 않습니다. 인‑메모리 데이터베이스는 저널링을 전혀 사용하지 않으며(저널이 메모리 내에만 존재합니다).

Journal types diagram

롤백 저널: SQLite의 안전 장치

각 데이터베이스에는 하나의 롤백‑저널 파일이 존재합니다:

  • 데이터베이스와 동일한 디렉터리에 저장됩니다.
  • 데이터베이스 파일 이름에 -journal을 붙여서 이름이 지정됩니다.
  • 쓰기 트랜잭션이 시작될 때 생성됩니다.
  • 트랜잭션이 끝나면(기본 설정) 삭제됩니다.

롤백 저널은 데이터베이스 페이지의 이전 이미지를 저장하므로, 문제가 발생했을 때 SQLite가 데이터베이스를 복원할 수 있습니다.

롤백 저널 구조

(원본 내용은 여기서 끝났으며, 필요에 따라 롤백 저널의 디스크 레이아웃을 계속 설명할 수 있습니다.)

Write‑Ahead Log (WAL) 저널 개요

SQLite 저널은 로그 세그먼트로 구분됩니다.

WAL segment illustration

각 세그먼트는 다음으로 구성됩니다:

  • 세그먼트 헤더
  • 하나 이상의 로그 레코드

대부분의 경우 하나의 세그먼트만 존재하며, 여러 세그먼트는 특수한 상황에서만 나타납니다.

세그먼트 헤더 – 첫 번째 방어선

각 세그먼트 헤더는 여덟 개의 매직 바이트로 시작합니다:

D9 D5 05 F9 20 A1 63 D7

이 바이트들은 오직 무결성 검사를 위해 존재합니다.

Segment header fields

헤더에는 또한 다음 정보가 저장됩니다:

  • 로그 레코드 수 (nRec)
  • 체크섬 계산을 위한 무작위 값
  • 원본 DB 페이지 수
  • 디스크 섹터 크기
  • DB 페이지 크기

헤더는 항상 정확히 하나의 디스크 섹터를 차지하며, 모든 값은 빅‑엔디언 형식으로 저장됩니다.

저널 보존 모드

기본적으로 SQLite는 커밋 또는 롤백 후 저널 파일을 삭제합니다. 다음 모드들을 사용해 동작을 변경할 수 있습니다:

모드설명
DELETE기본값 – 각 트랜잭션 후 저널 파일을 제거합니다.
PERSIST저널 파일은 유지하지만 사용 사이에 헤더를 무효화합니다.
TRUNCATE각 트랜잭션 후 저널 파일을 길이 0으로 잘라냅니다.

배타적 잠금 모드에서는 저널 파일이 트랜잭션 간에 지속되지만, 헤더는 사용 사이에 무효화되거나 잘려집니다.

비동기 트랜잭션 (안전하지 않지만 빠름)

SQLite는 내구성을 희생하고 속도를 높이는 비동기 모드를 지원합니다:

  • 저널 및 DB 파일이 디스크에 절대 플러시되지 않습니다.
  • 트랜잭션이 훨씬 빠르게 완료됩니다.
  • nRec 값이 ‑1 로 설정됩니다.
  • 복구는 메타데이터가 아닌 파일 크기에 의존합니다.

경고: 이 모드는 충돌 안전하지 않으며 개발이나 테스트 환경에서만 사용해야 합니다. 성능 향상이 데이터 손실 위험보다 클 때만 적용하십시오.

왜 이 레이어가 중요한가

  • 공간은 버려지지 않고 재활용됩니다.
  • 안전은 정밀하고 최소한의 메타데이터로 달성됩니다.
  • 암시적인 것이 없습니다; 모든 것이 명시적으로 추적됩니다.
  • 복구 로직은 파일 구조에 직접 인코딩됩니다.

SQLite와 관련된 나의 실험 및 실습 예제는 여기에서 확인할 수 있습니다:
lovestaco/sqlite – SQLite examples

참고 문헌

  • SQLite Database System: Design and Implementation – Sibsankar Haldar (n.d.)

FreeDevTools
👉 확인해 보세요: FreeDevTools

피드백이나 기여를 환영합니다! 이 프로젝트는 온라인에 있으며, 오픈소스이고, 누구든지 사용할 수 있습니다.

GitHub에서 별표를 눌러 주세요: HexmosTech/FreeDevTools

Back to Blog

관련 글

더 보기 »

SQLite에서 기본을 넘어선 저널

소개 안녕하세요, 저는 마네시와르입니다. 현재 저는 FreeDevTools 온라인을 구축하고 있습니다 – 모든 개발자 도구, 치트 코드, 그리고 TL;D를 모아 놓은 무료 오픈‑소스 허브입니다.

SQLite 내부: 파일 이름 지정

이 장은 SQLite의 가장 낮은 수준까지 모두 확대합니다—디스크상의 바이트가 페이지가 되고, 페이지가 트리가 되며, 내구성이 저널링을 통해 보장됩니다.