← 블로그 목록
SQLitePostgreSQL데이터베이스서버리스사이드프로젝트

SQLite vs PostgreSQL: 사이드 프로젝트 DB, 언제 옮겨야 하나

SQLite에서 PostgreSQL로 옮길 시점을 데이터 양이 아니라 쓰기 동시성과 배포 구조로 판단하는 기준, 그리고 이전 시 새로 생기는 숙제를 정리했습니다.

Vibeollio 팀-

데이터 양이 문제가 되는 경우는 드물다

사이드 프로젝트를 SQLite로 시작했다가 "언제 PostgreSQL로 옮겨야 하나" 고민하는 시점이 옵니다. 이때 흔히 데이터 건수를 기준으로 삼는데, 실제로 갈림길이 되는 건 데이터 양이 아닙니다.

SQLite는 이론상 수백 테라바이트까지 담을 수 있고, 수십만 건 규모의 조회는 인덱스만 제대로 걸려 있으면 충분히 빠릅니다. 옮겨야 하는 이유는 거의 항상 다른 곳에 있습니다. 쓰기 동시성과 배포 구조입니다.

근본적인 차이: 파일이냐 서버냐

SQLite는 서버가 없습니다. 애플리케이션 프로세스가 데이터베이스 파일을 직접 열어 읽고 씁니다. 설치도, 접속 정보도, 포트도 필요 없습니다. 백업은 파일 복사입니다.

PostgreSQL은 별도 프로세스로 돌고 애플리케이션은 네트워크로 접속합니다. 여러 클라이언트가 동시에 붙을 수 있고, 그 관리를 데이터베이스가 담당합니다.

이 한 가지 차이에서 나머지 대부분이 파생됩니다.

쓰기 동시성이 첫 번째 갈림길

SQLite는 같은 순간에 쓰기를 하나만 허용합니다. WAL 모드를 켜면 읽기와 쓰기가 서로를 막지 않게 되지만, 쓰기끼리는 여전히 줄을 섭니다.

PRAGMA journal_mode = WAL;   -- 읽기와 쓰기가 서로 대기하지 않음
PRAGMA busy_timeout = 5000;  -- 쓰기 잠금 대기 시간(ms)

busy_timeout을 설정하지 않으면 잠금이 걸린 순간 바로 오류가 납니다. SQLite로 운영하면서 database is locked를 만나는 대부분의 경우가 이 설정 누락입니다.

읽기가 압도적으로 많은 서비스라면 이 제약이 문제가 되지 않습니다. 블로그, 문서 사이트, 조회 위주의 도구가 그렇습니다. 반대로 사용자마다 계속 쓰기가 발생하는 구조, 예를 들어 실시간 협업이나 잦은 상태 업데이트가 있는 앱이라면 쓰기 큐가 곧 병목이 됩니다.

두 번째 갈림길: 어디에 배포하는가

이쪽이 실무에서 더 자주 결정을 강제합니다.

SQLite는 파일이므로 애플리케이션과 같은 디스크에 있어야 합니다. 그런데 서버리스 플랫폼의 파일시스템은 대체로 일시적이고, 인스턴스마다 별개입니다. 파일에 쓴 내용이 다음 요청에서 사라지거나, 인스턴스마다 다른 데이터를 갖게 됩니다.

애플리케이션 인스턴스를 두 개 이상 띄우는 순간에도 같은 문제가 생깁니다. 각자 자기 파일을 보게 되니까요.

정리하면 SQLite가 편한 배포 형태는 하나의 서버(또는 컨테이너)가 하나의 디스크를 계속 붙들고 있는 구조입니다. 이 조건을 벗어나면 PostgreSQL처럼 네트워크로 접속하는 데이터베이스가 필요합니다. SQLite를 네트워크 서비스로 감싼 관리형 제품들도 있지만, 그 선택을 하는 순간 "서버 없는 단순함"이라는 장점은 이미 포기한 셈입니다.

타입과 기능의 차이

SQLite는 타입에 느슨합니다. 숫자 컬럼에 문자열을 넣어도 대체로 받아줍니다. 엄격하게 쓰고 싶으면 테이블을 STRICT로 선언할 수 있습니다.

CREATE TABLE posts (
  id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  views INTEGER NOT NULL DEFAULT 0
) STRICT;

PostgreSQL은 타입 검사가 엄격하고, 쓸 수 있는 타입이 훨씬 넓습니다. jsonb로 JSON을 색인해 질의하거나, 배열·범위 타입을 쓰거나, 확장을 붙여 전문 검색과 벡터 검색을 하는 것들이 여기 해당합니다.

또 하나 실무에서 체감되는 차이는 스키마 변경입니다. SQLite의 ALTER TABLE은 할 수 있는 일이 제한적이어서, 컬럼 타입 변경이나 제약 조건 수정은 새 테이블을 만들어 데이터를 옮기는 방식으로 우회해야 합니다. 마이그레이션 도구가 이를 대신 처리해주지만, 도구가 지원하지 않는 변경(예: CHECK 제약 수정)을 만나면 직접 손을 대야 합니다.

옮겨야 하는 신호

다음 중 하나라도 해당하면 이전을 검토할 시점입니다.

  • 인스턴스를 2개 이상 띄워야 한다
  • 서버리스 환경에 배포한다
  • 쓰기 요청이 몰리는 시간에 잠금 대기나 오류가 관측된다
  • 백그라운드 워커가 웹 서버와 다른 프로세스로 같은 데이터를 써야 한다
  • jsonb 질의, 전문 검색, 벡터 검색처럼 확장 기능이 필요하다
  • 읽기 전용 복제본을 두고 싶다

반대로 아래에 해당하면 굳이 옮길 이유가 없습니다.

  • 서버 한 대에서 계속 돌릴 계획이다
  • 조회가 대부분이고 쓰기는 드물다
  • 운영 부담을 최소로 유지하고 싶다

옮길 때 조심할 것

PostgreSQL로 옮기면 새 숙제가 생깁니다. 접속 수 관리입니다. PostgreSQL은 접속마다 프로세스를 쓰기 때문에 동시 접속 수에 한계가 있습니다. 서버리스처럼 인스턴스가 늘었다 줄어드는 환경에서는 커넥션 풀러를 앞에 두거나, 제공자가 주는 풀링 전용 접속 문자열을 써야 합니다.

데이터 이전 자체는 규모가 작다면 어렵지 않습니다. 다만 타입 매핑을 확인해야 합니다. SQLite에서 느슨하게 저장돼 있던 값들, 특히 날짜와 불리언이 문자열로 들어가 있는 경우가 흔합니다. 옮기기 전에 한 번 정리하는 편이 낫습니다.

처음부터 PostgreSQL로 시작하는 게 낫지 않나요?

배포 형태를 이미 알고 있다면 그게 맞습니다. 서버리스에 올릴 계획이거나 인스턴스를 여러 개 띄울 예정이라면 처음부터 PostgreSQL로 가는 편이 이전 비용을 아낍니다. 반대로 무엇을 만들지도 확실하지 않은 초기 단계라면, 설정이 필요 없는 SQLite로 시작해 아이디어 검증에 시간을 쓰는 편이 합리적입니다. 로컬 개발은 SQLite, 배포는 PostgreSQL처럼 나누는 방식은 권하지 않습니다. 두 환경의 차이에서 오는 버그를 배포 후에 발견하게 됩니다.

SQLite로 운영하면 데이터가 날아갈 위험이 크지 않나요?

파일 하나라는 점 때문에 불안하게 느껴지지만, 위험의 성격은 다른 데이터베이스와 크게 다르지 않습니다. 중요한 건 백업 주기입니다. 파일 복사만으로 백업이 되므로 오히려 자동화가 간단합니다. 다만 실행 중에 파일을 그냥 복사하면 손상될 수 있으니, SQLite가 제공하는 백업 명령이나 스냅샷 기능을 쓰는 것이 맞습니다.

둘을 같이 쓰는 구성도 있나요?

있습니다. 주 데이터는 PostgreSQL에 두고, 자주 바뀌지 않는 참조 데이터나 캐시 성격의 데이터를 애플리케이션에 SQLite 파일로 붙여 배포하는 방식입니다. 다만 초기 프로젝트에서 이 구성을 택하면 관리 대상이 둘로 늘어납니다. 필요가 분명해진 다음에 도입하는 편이 낫습니다.

결정을 미룰 수 있는 방법

두 데이터베이스 모두 지원하는 ORM이나 쿼리 빌더를 쓰면 스키마와 쿼리를 크게 바꾸지 않고 옮길 수 있습니다. 물론 특정 데이터베이스 고유 기능을 쓰기 시작하면 그만큼 종속이 생기므로, 초기에는 표준 SQL 범위에서 머무는 것이 선택을 열어둡니다.

만든 프로젝트가 돌아가는 상태라면 Vibeollio에 프로젝트 등록해서 공개해보세요. 실제 사용자가 붙기 시작하면 예상과 다른 지점에서 부하가 걸리는데, 그 지점을 확인한 다음에 데이터베이스를 결정하는 편이 미리 고민하는 것보다 정확합니다.