처리중입니다. 잠시만 기다려주세요.
TTJ 코딩클래스
정규반 단과 자료실 테크 뉴스 코딩 퀴즈
테크 뉴스
Hacker News 2026.06.07 85

SQLite에서 UUID를 기본키로 쓰면 안 되는 이유 — 무작위 키가 성능을 갉아먹는 원리

Hacker News 원문 보기
SQLite에서 UUID를 기본키로 쓰면 안 되는 이유 — 무작위 키가 성능을 갉아먹는 원리

'그냥 UUID 쓰면 편하잖아요'의 함정

새 테이블을 만들 때 기본키(primary key)를 뭘로 할지 고민하다가, 많은 분들이 UUID 를 골라요. 550e8400-e29b-41d4-a716-446655440000 같은 긴 무작위 문자열 말이에요. 이게 매력적인 이유가 있어요. 서버가 여러 대여도 충돌 없이 ID를 만들 수 있고, 순차 증가하는 숫자처럼 'ID 100번 다음은 101번이겠네' 하고 남이 추측하기도 어렵거든요. 그래서 분산 시스템이나 보안이 신경 쓰이는 곳에서 즐겨 써요.

그런데 SQLite 에서 UUID를 기본키로 쓰면, 데이터가 쌓일수록 성능이 슬금슬금 나빠지는 함정에 빠질 수 있어요. 왜 그런지 이해하려면 SQLite가 데이터를 어떻게 저장하는지부터 알아야 해요.

B-트리와 '무작위 삽입'의 충돌

SQLite는 테이블을 B-트리(B-tree) 라는 자료구조로 저장해요. 핵심은 이 트리가 기본키 순서대로 정렬된 상태로 데이터를 디스크의 '페이지(page)'라는 고정 크기 블록에 차곡차곡 담는다는 거예요. 특히 SQLite에서 정수 기본키(INTEGER PRIMARY KEY)는 rowid라는 특별한 자리에 들어가서, 새 행은 항상 '맨 끝'에 추가돼요. 순서대로 1, 2, 3... 늘어나니까 마지막 페이지에만 살짝 덧붙이면 끝이라 굉장히 효율적이죠.

문제는 UUID예요. UUID(특히 v4)는 완전히 무작위라서, 새로 만든 키가 트리의 맨 끝이 아니라 한가운데, 앞쪽, 뒤쪽 아무 데나 끼어들어야 해요. 정렬을 유지해야 하니까요. 그러면 어떤 일이 벌어지냐면, 이미 꽉 찬 페이지 사이에 억지로 값을 밀어넣어야 하고, 자리가 없으면 페이지를 둘로 쪼개는 페이지 분할(page split) 이 일어나요. 이게 자주 발생하면 데이터가 디스크 여기저기 흩어지는 단편화(fragmentation) 가 심해지고, 캐시 효율도 떨어지고, 데이터베이스 파일 크기도 불필요하게 부풀어요. 삽입이 느려지는 건 물론이고요.

게다가 UUID를 텍스트(36글자 문자열) 로 저장하면 정수보다 훨씬 많은 공간을 먹어요. 기본키는 모든 인덱스에 같이 복제돼서 들어가기 때문에, 이 무게가 전체 DB에 곱해져서 퍼져요.

그럼 어떻게 해야 하나

해결책은 크게 두 갈래예요. 첫째, UUID를 굳이 써야 한다면 무작위 대신 '순서가 있는' 형태를 쓰세요. UUIDv7 이나 ULID 같은 게 대표적인데, 이것들은 앞부분에 시간 정보(timestamp)를 담아서 시간 순으로 대략 정렬돼요. 그러면 새 키가 대체로 '맨 끝'에 추가되니까, 순차 정수와 비슷하게 페이지 분할 없이 깔끔하게 들어가요. 보안성과 분산 친화성은 챙기면서 삽입 성능 문제는 피하는 절충안이죠.

둘째, 저장 형식을 텍스트가 아니라 16바이트 BLOB(이진 데이터)으로 저장하세요. 36글자 문자열을 16바이트로 줄이면 용량이 절반 이하로 떨어지고 비교도 빨라져요. 더 나아가, 내부적으로는 INTEGER PRIMARY KEY(rowid)를 진짜 기본키로 쓰고, UUID는 별도 컬럼에 유니크 인덱스를 걸어서 외부 노출용으로만 쓰는 패턴도 많이 권장돼요. 그러면 내부 저장은 빠른 정수로, 외부 식별자는 안전한 UUID로 두 마리 토끼를 잡을 수 있어요.

업계 맥락과 시사점

사실 이 문제는 SQLite만의 일은 아니에요. MySQL InnoDB도 클러스터형 인덱스를 쓰기 때문에 무작위 UUID를 기본키로 박으면 똑같이 페이지 분할로 고생해요. 그래서 '시간 정렬되는 UUIDv7/ULID를 쓰자'는 흐름이 업계 전반의 정석으로 자리 잡는 중이에요. 반대로 PostgreSQL은 힙(heap) 기반이라 영향이 덜한 편이라, 'DB마다 저장 구조가 다르니 기본키 전략도 달라야 한다'는 교훈도 같이 얻을 수 있어요.

요즘 SQLite가 로컬 우선(local-first) 앱이나 엣지 환경에서 다시 인기를 끌고 있잖아요. 그만큼 이런 디테일이 실무에 직접 와닿아요.

핵심은 이거예요: UUID 자체가 나쁜 게 아니라, '무작위 UUID를 정렬형 B-트리의 기본키로 박는 조합'이 문제다. 시간 정렬 UUID와 BLOB 저장이면 대부분 해결돼요. 여러분 프로젝트의 기본키는 지금 어떤 방식인가요? 혹시 무심코 v4 UUID를 텍스트로 박아두진 않았나요?


🔗 출처: Hacker News

이 뉴스가 유용했나요?

TTJ 코딩클래스 정규반

월급 외 수입,
코딩으로 만들 수 있습니다

17가지 수익 모델을 직접 실습하고, 1,300만원 상당의 자동화 도구와 소스코드를 받아가세요.

144+실전 강의
17개수익 모델
4.9수강생 평점
정규반 자세히 보기

"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"

실제 수강생 후기
  • 비전공자도 6개월이면 첫 수익
  • 20년 경력 개발자 직강
  • 자동화 프로그램 + 소스코드 제공

매일 AI·개발 뉴스를 받아보세요

주요 테크 뉴스를 매일 아침 이메일로 전해드립니다.

스팸 없이, 언제든 구독 취소 가능합니다.