
SQLite vs PostgreSQL: 데이터 크기보다 동시 쓰기가 경계를 만든다

새 애플리케이션이 한 호스트에서 SQL을 실행하고 로컬 데이터 파일에 접근하며, 쓰기 요청이 잠깐씩 차례를 기다려도 된다면 SQLite가 적합하다. 여러 애플리케이션 호스트가 같은 데이터에 직접 접속해야 하거나 겹친 쓰기 요청의 대기 시간이 서비스 요구를 넘는다면 PostgreSQL이 더 자연스럽다. 저장할 행의 수보다 SQL 실행 위치와 쓰기 경쟁의 형태를 먼저 따져야 하는 이유다.
하루 동안 발생하는 쓰기 횟수만으로 경쟁을 판단할 수는 없다. 갱신이 자주 일어나도 각 트랜잭션이 짧고 도착 시점이 분산되면 한 작성자가 끝난 뒤 다음 작성자가 진행할 수 있다. 반대로 전체 데이터가 작고 쓰기 횟수가 적어도 여러 작업이 같은 순간에 몰리거나 트랜잭션이 오래 열려 있으면 대기가 길어진다. 데이터의 크기는 저장 공간과 질의 비용을 따질 때 중요하지만 동시 쓰기의 구조를 대신 설명하지는 않는다.
네트워크 경계는 이용자가 아니라 SQL 실행 위치에 있다
SQLite의 사용 환경 안내는 SQL을 실행하는 코드와 데이터가 같은 장비에 있고 작성자 간 경쟁이 낮은 경우를 SQLite에 적합한 조건으로 제시한다. 여러 컴퓨터의 프로그램이 같은 데이터베이스에 직접 SQL을 보내야 한다면 클라이언트·서버형 엔진을 고려하도록 권한다. 이때 기준이 되는 애플리케이션은 웹사이트에 접속한 이용자의 브라우저가 아니라 실제 SQL 문장을 실행하는 서버 프로세스다.
이용자가 전국에서 접속하더라도 웹 서버 한 대가 요청을 받아 자기 로컬 저장소의 파일을 연다면 SQLite를 쓸 수 있다. 이용자와 웹 서버 사이에 네트워크가 있다는 사실은 데이터베이스 엔진과 파일 사이에 네트워크가 있다는 뜻이 아니다. 반면 웹 서버를 서로 다른 호스트에 늘리고 각 서버가 공유 저장소의 같은 파일을 직접 열게 하면 파일 잠금의 정확성과 지연이 데이터베이스 동작을 좌우한다. 이 구조에서는 서버형 데이터베이스가 파일 접근을 전담하는 편이 설계에 맞는다.
SQLite로도 여러 서버의 요청을 한 애플리케이션 서버에 모아 처리하는 구조를 만들 수 있다. 이 경우 데이터베이스 파일을 여는 주체는 한 호스트에 남아 있지만, 그 애플리케이션 서버가 요청의 집중 지점이 된다. 독립적으로 서버 수를 늘릴 계획인지, 데이터 접근을 한곳에 모아도 되는지에 따라 선택이 달라진다. ‘서버가 여러 대’라는 표현만으로는 부족하고 어느 서버가 실제로 SQL을 실행하는지까지 그려야 한다.
WAL은 읽기와 쓰기를 겹치게 하지만 작성자는 차례를 지킨다
SQLite의 WAL 문서에 따르면 WAL 모드에서는 읽기와 쓰기가 동시에 진행될 수 있지만 작성자는 한 번에 하나뿐이다. 읽는 작업은 자기 트랜잭션이 시작될 때의 기록 지점을 기준으로 데이터를 보고, 쓰는 작업은 변경 내용을 WAL 파일 끝에 추가한다. 따라서 읽기 요청이 많은 서비스라는 이유만으로 쓰기 경쟁이 심하다고 판단할 수 없고, 읽기가 계속된다는 이유만으로 쓰기가 막힌다고 볼 수도 없다.
쓰기 요청의 총량보다 중요한 것은 작성자 자리를 점유하는 시간이다. 예를 들어 조건부로, 짧은 주문 기록이 시간차를 두고 들어오면 각 요청은 순서대로 빠르게 끝날 수 있다. 같은 수의 요청이라도 외부 결제를 기다리는 동안 쓰기 트랜잭션을 열어 두거나 여러 갱신을 한 트랜잭션에 묶어 오래 유지하면 뒤의 작성자들이 기다린다. 동시 접속자 수나 평균 요청량만 보는 대신 실제 쓰기 트랜잭션의 길이와 대기 시간 분포를 살펴야 한다.
WAL에서 읽기가 길어지는 문제는 별도로 나타난다. WAL의 변경 내용을 원래 데이터베이스 파일로 옮기는 체크포인트는 오래 열린 읽기 트랜잭션이 참조하는 지점을 지나갈 수 없다. 읽기 작업이 끊이지 않아 체크포인트를 끝내지 못하면 WAL 파일이 계속 커지고, 파일이 커질수록 읽기 비용도 늘 수 있다. 작성자 대기와 체크포인트 지연은 원인이 다르므로 하나의 ‘동시성 문제’로 뭉뚱그리면 진단이 흐려진다.
WAL에는 같은 호스트라는 경계가 있다. 읽는 프로세스들이 WAL 색인을 공유 메모리로 사용하므로 서로 다른 호스트가 하나의 WAL 데이터베이스를 네트워크 파일시스템에서 여는 방식은 지원되지 않는다. SQLite 자체는 다른 저널 모드에서 네트워크 파일시스템을 사용할 수 있지만 그 경우에도 파일 잠금의 신뢰성과 지연을 따져야 한다. 공유 저장소를 붙이면 로컬 파일형 데이터베이스가 곧바로 여러 서버용 데이터베이스가 되는 것은 아니다.
파일 하나만 복사하면 언제나 백업이 완성된다고 가정해서도 안 된다. WAL 모드에서 WAL 파일은 데이터베이스의 지속 상태에 속하며, 원본 파일과 분리하면 이미 커밋된 변경을 잃을 수 있다. 백업과 파일 이동 절차는 실제 저널 모드와 연결 상태에 맞춰 설계해야 한다.
PostgreSQL은 독립적인 갱신을 함께 처리해도 같은 행에서는 기다린다
PostgreSQL은 여러 애플리케이션 호스트의 연결을 데이터베이스 서버가 받아 처리한다. PostgreSQL의 MVCC 설명은 각 SQL 문장이 데이터의 스냅샷을 보며 일반적인 읽기와 쓰기가 서로를 막지 않는다고 설명한다. 데이터 파일을 각 애플리케이션 서버가 직접 열 필요가 없다는 서버형 구조와, 읽기 작업이 갱신 작업의 잠금을 기다리지 않는 동시성 모델은 구별해서 이해할 만하다.
그렇다고 PostgreSQL의 모든 쓰기가 아무 제약 없이 나란히 끝나는 것은 아니다. PostgreSQL의 행 잠금 문서에 따르면 같은 행을 수정하거나 잠그려는 트랜잭션은 충돌하는 잠금이 풀리기를 기다릴 수 있다. 서로 다른 주문을 갱신하는 작업과 모든 주문이 하나의 재고 행을 변경하는 작업은 같은 쓰기 요청 수라도 대기 양상이 다르다. 한 자원에 갱신이 집중된다면 엔진 교체만으로 그 행의 경쟁이 사라지지는 않는다.
따라서 여러 작업자가 독립적인 레코드를 변경할 수 있는지, 모두 같은 레코드나 순번을 만지는지 살펴볼 필요가 있다. 전자라면 서버형 접속과 행 단위 경쟁 관리가 PostgreSQL의 선택 이유가 된다. 후자라면 짧은 트랜잭션, 작업 분할, 충돌 뒤 재시도 같은 애플리케이션 설계도 함께 중요해진다. PostgreSQL의 장점은 무한한 병렬 쓰기 능력이 아니라 서로 다른 작업을 한 데이터베이스 서비스에서 조정할 수 있다는 데 있다.
공개 벤치마크가 답한 질문은 단일 장비의 처리량이다
공개 쓰기 벤치마크 저장소는 같은 장비와 SSD, 같은 스키마에서 SQLite WAL 구성과 로컬 PostgreSQL을 비교한다. 단일 연결의 순차 삽입에서는 이 실험의 SQLite 구성이 더 높은 처리량을 보였고, PostgreSQL은 연결을 늘린 별도의 동시 작성 시험에서 처리량이 증가했다. 후자는 SQLite에 같은 동시 작성 부하를 주는 맞대결이 아니라 PostgreSQL 구성 자체의 확장 양상을 측정한 결과다.
설정도 결과의 일부다. 실험은 SQLite에 synchronous=NORMAL, PostgreSQL에 synchronous_commit=on을 사용했고, 접근 경로도 내장 SQLite 호출과 로컬 PostgreSQL 연결로 다르다. SQLite WAL의 NORMAL 설정에서는 정전이나 강제 재시작 뒤 최근 커밋이 되돌아갈 수 있으므로 두 결과를 동일한 장애 후 보존 조건의 순수 엔진 성능 차이로 읽을 수 없다. 빠른 로컬 호출이라는 장점과 내구성 설정의 차이가 한 결과 안에 함께 들어 있다.
시험 범위에는 원격 PostgreSQL의 네트워크 지연, 여러 애플리케이션 서버가 보내는 쓰기, 매우 큰 데이터, 복잡한 조인과 집계가 포함되지 않았다. 그러므로 순차 삽입의 승자를 실제 서비스의 승자로 옮길 수 없다. 벤치마크는 단일 호스트에서 호출 경로와 설정이 처리량에 미치는 영향을 보여 주지만, 여러 서버로 확장한 배포 구조의 운영비와 경합 패턴까지 재현하지는 않는다. 특히 같은 행을 동시에 고치는 작업의 대기 시간은 실험에 제시된 전체 처리량만으로 알기 어렵다.
백업과 장애 복구까지 포함하면 선택 기준이 완성된다
한 호스트에 남을 수 있고 쓰기 트랜잭션을 짧게 유지할 수 있다면 SQLite는 별도 데이터베이스 서버를 운영하지 않아도 되는 선택이다. 다만 파일의 권한과 백업, 디스크 장애 뒤 복구를 애플리케이션 운영자가 맡아야 한다. 서버 프로세스가 없다는 것은 운영할 대상이 없다는 뜻이 아니라 데이터 보존을 책임지는 위치가 다르다는 뜻이다.
PostgreSQL은 여러 애플리케이션 호스트가 공통 서비스를 사용해야 할 때 운영 구조가 분명해진다. 대신 데이터베이스 서버 또는 관리형 서비스의 접속 설정, 장애 대응, 백업과 복구가 별도의 책임으로 생긴다. 관리형 서비스를 이용해 서버 관리 업무를 줄이더라도 애플리케이션과 데이터베이스 사이의 네트워크 지연과 연결 실패를 다루는 책임은 남는다. 어느 쪽이든 운영 책임이 사라지는 것이 아니라 배치되는 위치가 달라진다.
선택 순서는 배포 구조에서 시작한다. SQL을 실행하는 프로세스와 데이터 파일이 같은 호스트에 머물 수 있는지, 쓰기 트랜잭션이 겹쳤을 때 차례를 기다릴 수 있는지, 여러 갱신이 같은 행을 두고 충돌하는지를 차례로 판단한다. 그 뒤에 백업과 복구를 맡을 주체, 데이터 크기와 질의 요구를 더하면 된다. 로컬 파일과 짧은 쓰기에 맞는 구조라면 SQLite가 간결하고, 호스트 간 공통 접속과 독립적인 동시 갱신이 핵심이라면 PostgreSQL의 서버형 구조가 맞다.
함께 읽기:
관련 기사
뉴스레터 구독
최신 Web3, AI, 암호화폐 뉴스를 이메일로 받아보세요.




