데이터베이스의 두 가지 형태
SQLite와 MySQL은 둘 다 SQL을 말하고 테이블에 행을 저장하지만, 시스템에 끼워 넣는 방식 자체가 완전히 다릅니다. SQLite는 라이브러리 입니다. 애플리케이션이 직접 링크해서 디스크의 파일을 읽고 쓰죠. 반면 MySQL은 서버 입니다. 별도 프로세스로 떠 있고, 소켓이나 네트워크를 통해 접속해서 사용합니다.
이 차이 하나가 나머지 모든 것을 결정합니다. 설치 방식, 동시 쓰기를 몇 개까지 받을 수 있는지, 백업은 어떻게 뜨는지, 어떻게 배포할지까지요. 사람들이 SQLite와 MySQL을 비교하면서 던지는 질문들 대부분은, 사실 임베디드 데이터베이스와 클라이언트-서버 구조의 차이에 대한 질문입니다.
-- SQLite: ファイルを開けば、データベースが手に入る。
sqlite3 app.db
-- MySQL: 起動中のサーバーに接続する。
mysql -h localhost -u root -p
SQLite 명령어는 파일을 열거나 새로 만듭니다. 반면 MySQL 명령어는 이미 실행 중이고, 설정이 끝났으며, 로그인을 받아주는 프로세스에 연결을 시도하는 거죠.
아키텍처: 임베디드 데이터베이스 vs 클라이언트-서버
SQLite를 쓰는 앱에서는 DB 엔진이 프로그램 내부에서 함께 돌아갑니다. 별도의 포트도, 데몬도, systemctl start도 없습니다. sqlite3 라이브러리 호출이 디스크의 파일에서 페이지를 직접 읽고 씁니다.
MySQL은 정반대입니다. mysqld 서버가 데이터를 보관하고, 커넥션을 관리하며, 권한을 검사하고, 쿼리 플래너를 돌리고, 락도 처리합니다. 여러분의 앱은 SQL 문자열을 네트워크 너머로 보내고 결과 행을 돌려받는 클라이언트일 뿐이죠.
이 차이가 실무에서 드러나는 지점들:
- 배포. SQLite는 앱과 함께 배포됩니다 — 바이너리 하나, 파일 하나면 끝. MySQL은 별도 서버를 설치하고, 보안 설정하고, 모니터링하고, 백업까지 챙겨야 합니다.
- 네트워크 접근. MySQL은 포트를 열어두기 때문에 여러 애플리케이션 서버가 같은 데이터베이스에 붙을 수 있습니다. SQLite는 같은 머신에서 한 프로세스(혹은 협력하는 몇 개의 프로세스)가 쓴다고 전제합니다.
- 권한. MySQL에는 사용자, 역할,
GRANT문이 있습니다. SQLite에서 권한이라고 할 만한 건 DB 파일의 OS 파일 권한이 전부입니다.
어느 쪽이 "더 낫다"는 건 없습니다. 푸는 문제가 다를 뿐이에요.
동시성과 쓰기 작업
진짜 차이가 갈리는 지점이 바로 여기입니다. MySQL의 InnoDB 엔진은 행 단위 락(row-level locking)을 씁니다. 덕분에 여러 커넥션이 서로 다른 행에 동시에 쓰기를 해도 서로를 막지 않습니다.
SQLite는 쓰기를 데이터베이스 단위에서 직렬화합니다. 한 번에 한 명의 쓰기 작업자만 허용, 그게 끝입니다. 읽기 작업은 (특히 WAL 모드라면) 쓰기와 나란히 돌 수 있지만, 두 번째 쓰기 작업은 자기 차례가 올 때까지 기다려야 합니다.
-- SQLite: 多くの読み取り側に対しては問題なく動作し、書き込みは一度に1つのみ。
PRAGMA journal_mode = WAL;
-- MySQL: 複数の書き込み側、細粒度のロック。
-- (特別な設定は不要 — InnoDBがデフォルトで対応しています。)
데스크톱 툴이나 모바일 앱, 소규모 CMS처럼 프로세스 한두 개가 적당히 쓰기 작업을 하는 정도라면 SQLite의 직렬화된 쓰기 방식도 충분히 빨라서 체감조차 안 됩니다. 하지만 수백 개의 커넥션이 동시에 주문을 인서트하고 세션을 업데이트하는 트래픽 많은 웹 서비스라면 얘기가 달라지죠. 이때는 MySQL의 행 단위 락(row-level locking)이 "잘 돌아간다"와 "전부 락 하나 뒤에 줄 서 있다"를 가르는 결정적인 차이가 됩니다.
데이터 타입
MySQL은 타입이 길고 엄격하게 정해져 있습니다. TINYINT, INT, BIGINT, VARCHAR(n), DATETIME, DECIMAL(p,s), BLOB, JSON 등 종류도 다양하죠. 컬럼을 INT로 선언했다면 문자열을 넣는 순간 MySQL이 가차 없이 거부합니다.
반면 SQLite는 타입 친화도(type affinity) 라는 개념을 씁니다. 컬럼 타입은 강제 규칙이 아니라 일종의 힌트일 뿐입니다. INTEGER 컬럼에 문자열을 넣어도 SQLite는 그냥 저장해 버립니다(3.37 버전부터 추가된 STRICT 테이블을 명시적으로 사용하지 않는 한 말이죠).
두 행 모두 정상적으로 삽입됩니다. 프로토타이핑할 때는 이런 유연함이 편리하지만, 데이터베이스 수준의 타입 안전성을 기대했다면 당황스러울 수 있습니다. SQLite에서 MySQL 같은 엄격한 타입 검사를 원한다면 STRICT 테이블을 사용하세요.
실제로 마주치는 SQLite vs MySQL 문법 차이
SELECT, JOIN, WHERE, GROUP BY 같은 기본 SQL은 거의 동일합니다. 차이가 나는 부분은 몇 가지로 정리됩니다.
- 자동 증가 기본 키. SQLite는
INTEGER PRIMARY KEY만 써도 기본적으로 자동 증가합니다. MySQL은INT AUTO_INCREMENT PRIMARY KEY를 사용합니다. - 문자열 따옴표. MySQL은 식별자에 백틱(
`table`)을 허용합니다. SQLite는 SQL 표준을 따라 큰따옴표("table")를 사용합니다. - 날짜 함수. MySQL에는
NOW(),CURDATE(),DATE_ADD()가 있고, SQLite에는datetime('now'),date('now'),datetime('now', '+1 day')가 있습니다. LIMIT문법. 둘 다LIMIT n OFFSET m을 지원하므로 이 부분은 호환됩니다.- 불리언 타입. MySQL에는
BOOLEAN이 있지만 사실TINYINT(1)의 별칭입니다. SQLite는INTEGER컬럼에0과1로 불리언 값을 저장합니다.
-- MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME DEFAULT NOW()
);
-- SQLite
CREATE TABLE users (
id INTEGER PRIMARY KEY,
created_at TEXT DEFAULT (datetime('now'))
);
성격은 같지만 키워드가 조금 다르다고 보면 됩니다. 머릿속 모델은 그대로 가져가고, 문법만 살짝 손보면 됩니다.
성능: 질문에 따라 답이 달라진다
"SQLite가 MySQL보다 빠른가요?"라는 질문에는 정답이 하나로 떨어지지 않습니다.
단일 프로세스가 로컬에서 읽고 쓰는 상황이라면 SQLite가 더 빠른 경우가 많습니다. 네트워크를 타지 않고, 프로세스 간 통신도 없고, 쿼리 파서가 별도 주소 공간에서 돌아가지도 않으니까요. SQLite의 SELECT는 사실상 함수 호출 한 번에 가깝습니다.
반대로 같은 DB에 여러 커넥션이 동시에 쓰기를 한다면, 행 단위 잠금을 지원하는 MySQL이 앞서갑니다. SQLite는 쓰기 작업이 한 번에 하나(single-writer)라는 구조라서, 이런 워크로드에서는 경합이 금방 드러납니다.
읽기 위주의 워크로드에 WAL 모드까지 켜두면 SQLite도 의외로 잘 버팁니다. 리더끼리는 서로를 막지 않고, 단일 라이터도 막지 않거든요. 실제로 SQLite로 트래픽을 받아내는 프로덕션 사이트도 적지 않습니다.
인터넷에서 본 벤치마크 한 줄로 결정하지 마세요. 본인 서비스의 실제 접근 패턴을 보고 골라야 합니다.
어떤 상황에서 무엇을 고를까
다음과 같다면 SQLite를 선택하세요:
- 하나의 애플리케이션 옆에 DB가 붙어 있는 구조 (모바일 앱, 데스크톱 툴, CLI, 작은 웹사이트).
- 설정 없이 그냥 파일만 배포하면 끝나는 구조를 원할 때.
- 쓰기보다 읽기가 압도적으로 많거나, 쓰기 자체가 드문 경우.
- 프로덕션 SQL을 그대로 흉내 내는 임베디드 테스트 DB가 필요할 때.
- 프로토타이핑 단계에서 아직 서버 운영까지 신경 쓰고 싶지 않을 때.
다음과 같다면 MySQL을 선택하세요:
- 여러 애플리케이션 서버가 하나의 DB를 공유해야 할 때.
- 동시에 쓰기를 시도하는 클라이언트가 많을 때.
- 세분화된 사용자 권한과 역할 관리가 필요할 때.
- 처음부터 MySQL을 전제로 하는 스택(LAMP, 흔한 관리형 클라우드 구성 등) 위에서 개발할 때.
- 복제, 특정 시점 복구(PITR), 모니터링 같은 운영 도구가 필수 요건일 때.
대략적인 감으로는 이렇게 보면 됩니다. 저장 요구사항을 "앱 하나, 디스크 하나"라고 표현할 수 있으면 SQLite로 충분합니다. "서비스 하나에 운영자가 붙어 있다"라고 표현해야 한다면 MySQL(혹은 PostgreSQL) 쪽으로 가세요.
SQLite에서 MySQL로 마이그레이션하기
처음에는 SQLite로 시작했다가 나중에 MySQL로 옮기는 건 이미 많은 사람이 가본 길이고, 충분히 합리적인 계획입니다. 스키마는 약간만 손보면 그대로 옮겨가고, 데이터는 SQLite CLI의 .dump 명령으로 깔끔하게 뽑을 수 있습니다. 실제로 손볼 부분은 대부분 자동 증가(auto-increment) 문법, 날짜 함수, 그리고 MySQL에 직접적인 대응이 없는 SQLite 전용 기능들입니다. 모양이 좀 특이한 부분 인덱스, WITHOUT ROWID, STRICT 테이블 같은 것들이죠.
반대 방향, 즉 MySQL에서 SQLite로 가는 경우는 흔치는 않지만 역시 가능합니다. 보통 오프라인 분석용, 일부 데이터만 임베디드로 들고 다닐 때, 혹은 테스트 픽스처를 만들 때 이런 작업을 하게 됩니다.
핵심은 이겁니다. 지금 SQLite를 고른다고 해서 거기에 묶이는 게 아닙니다. 작성한 SQL도, 그동안 쌓은 이해도 그대로 따라옵니다.
다음 글: SQLite vs PostgreSQL
가장 흔한 비교 대상은 MySQL이지만, SQLite를 비교할 때 빠지지 않는 또 다른 DB가 PostgreSQL입니다. 그리고 차이점의 결도 또 다릅니다. 그 이야기는 다음 글에서 이어가겠습니다.
자주 묻는 질문
SQLite와 MySQL의 가장 큰 차이는 뭔가요?
SQLite는 임베디드 DB입니다. 앱이 단일 파일을 직접 읽고 쓰며, 별도 서버 프로세스가 없습니다. 반면 MySQL은 클라이언트-서버 구조라서 mysqld라는 별도 프로세스가 포트를 열어두고, 앱은 네트워크를 통해 거기에 접속합니다. 이 아키텍처 차이 하나가 두 DB의 거의 모든 트레이드오프를 만들어냅니다.
SQLite가 MySQL보다 빠른가요?
단일 프로세스에서 읽기와 가벼운 쓰기 작업만 한다면 SQLite가 빠른 경우가 많습니다. 네트워크 왕복도, 프로세스 간 통신 오버헤드도 없으니까요. 하지만 동시 쓰기가 많아지면 얘기가 다릅니다. SQLite는 DB 단위로 쓰기를 직렬화하기 때문에 이런 상황에선 MySQL이 압도적입니다. 결국 정답은 워크로드에 달려 있지, 엔진 그 자체에 있는 게 아닙니다.
어떤 경우에 MySQL 대신 SQLite를 쓰는 게 좋나요?
임베디드 앱, 모바일, 데스크톱 도구, CLI 유틸리티, 로컬 캐시, 테스트, 그리고 애플리케이션 서버가 하나뿐인 중소 규모 웹사이트라면 SQLite가 잘 맞습니다. 반대로 애플리케이션 서버 여러 대가 하나의 DB를 바라봐야 하거나, 사용자별 권한을 세밀하게 나눠야 하거나, 행 단위 잠금이 필요할 만큼 쓰기가 많은 워크로드라면 MySQL을 선택하는 게 맞습니다.
나중에 SQLite에서 MySQL로 마이그레이션할 수 있나요?
네, 실제로 흔한 경로입니다. CREATE TABLE, INSERT, SELECT 같은 기본 SQL 문법은 거의 호환되지만, 타입은 손봐야 합니다. 예를 들어 INTEGER PRIMARY KEY는 INT AUTO_INCREMENT로 바꿔야 하고, 날짜 함수나 WITHOUT ROWID, 부분 유니크 인덱스 같은 SQLite 전용 기능도 따로 처리해야 합니다. pgloader나 직접 작성한 덤프 스크립트로 대부분 자동화할 수 있습니다.