Notes
12분 읽기Tech

Room vs SQLite 성능과 선택 기준

Android와 Linux 환경에서 Room과 직접 SQLite 사용을 성능, 메모리, CPU, 벤치마크 신뢰도 관점으로 비교한 분석 노트.

Room vs SQLite 성능과 선택 기준

한 줄 요약

Android 앱에서는 Room을 기본값으로 두고 성능 critical path만 직접 SQLite로 분리하는 전략이 가장 현실적이다. Linux 서버나 임베디드 환경에서는 Room보다 직접 SQLite 바인딩이 자연스러운 기준선이다.

먼저 읽을 결론

Room과 SQLite는 같은 층의 기술이 아니다. SQLite는 C 기반 embedded SQL database engine이고, Room은 SQLite 위에서 DAO, entity mapping, migration, compile-time SQL verification, Flow/Coroutine 연동을 제공하는 AndroidX/Kotlin persistence layer다.

그래서 “Room이 SQLite보다 느린가?”라는 질문은 실제로는 다음 질문에 가깝다.

같은 SQLite 엔진을 사용할 때 Room의 generated DAO, 객체 매핑, 타입 변환, invalidation tracking, Coroutine/Flow 계층이 직접 SQLite API보다 얼마나 오버헤드를 추가하는가?

요약 판단은 다음과 같다.

환경/목표추천
일반 Android 앱 CRUDRoom 우선
Android + 대량 sync/cache/log ingestionRoom + hot path 직접 SQLite
Android + 극단적 CPU/메모리/latency 최적화직접 SQLite
Android + migration/팀 개발/유지보수 중요Room
Linux 서버/CLI/임베디드SQLite 직접 사용
Kotlin Multiplatform으로 Android/Linux DB 계층 공유Room KMP 고려 가능
플랫폼별 SQLite 버전 차이를 줄이고 싶음bundled SQLite driver 고려

핵심은 단순하다. Room은 Android 앱 개발의 안전성과 유지보수성을 크게 높인다. 직접 SQLite는 성능, 메모리, CPU를 끝까지 줄여야 할 때 유리하다. Room의 성능이 “나쁘다”기보다 추상화 비용이 있고, 그 비용이 hot path에서 보인다.

왜 저장했나

Android 로컬 저장소를 고를 때 Room과 SQLite 논쟁은 자주 반복된다. 문제는 대부분의 답이 “Room이 편하다” 또는 “SQLite가 빠르다”에서 멈춘다는 점이다.

이 노트는 판단 기준을 더 구체화한다. 공개 벤치마크 숫자, 공식 문서, AndroidX benchmark source, SQLite WAL 특성을 근거로 어떤 조건에서 Room의 비용이 의미 있게 커지는지, 어떤 조건에서는 유지보수 이득이 더 큰지 정리한다.

정리한 질문

Android와 Linux 환경에서 Room과 직접 SQLite 사용을 성능, 메모리, CPU 사용량, 벤치마크 데이터 기준으로 비교하면 어떤 결론이 나오는가? 일반 앱, 대량 데이터 처리, Kotlin Multiplatform, Linux 서버/임베디드 환경에서는 각각 무엇을 선택해야 하는가?

비교 대상 정의

Room과 SQLite는 DB 엔진끼리의 비교가 아니다.

항목RoomSQLite 직접 사용
정체SQLite 위의 AndroidX/Kotlin persistence abstractionC 기반 embedded SQL database engine
저장 포맷SQLite DB 파일SQLite DB 파일
쿼리 실행 엔진SQLiteSQLite
성능 차이의 원인DAO/generated code, 객체 매핑, 타입 변환, Flow/invalidation, Coroutine dispatch앱 코드가 Cursor/statement/driver 직접 제어
장점타입 안전성, 컴파일 타임 SQL 검증, migration, 생산성최소 오버헤드, Cursor streaming, 세밀한 튜닝
단점mapping/abstraction overhead코드량 증가, migration/검증 직접 구현

SQLite는 별도 서버가 없는 in-process, self-contained, transactional SQL database다. Room은 이 위에서 annotation 기반 DAO, entity mapping, migration, query validation을 제공한다. 따라서 Room을 쓰더라도 최종 저장 엔진은 SQLite다.

벤치마크 데이터

오래된 Android ORM benchmark

공개 GitHub 벤치마크 중 Room과 clean SQLite를 같은 Android 환경에서 비교한 자료가 있다. 단순 CRUD, 복잡한 CRUD, 균형형 CRUD를 평균 10회 측정했고 Samsung S7에서 실행됐다. 원문 기준 결과는 다음과 같다.

시나리오작업RoomSQLiteRoom / SQLite
SimpleWrite131502.62x
SimpleRead6994361.60x
SimpleUpdate170632.70x
SimpleDelete109801.36x
ComplexWrite5623861.46x
ComplexRead320121551.49x
ComplexUpdate7171923.73x
ComplexDelete4032841.42x
BalancedWrite133011461.16x
BalancedRead353223131.53x
BalancedUpdate7902133.71x
BalancedDelete5073181.59x

이 표의 합산 시간은 Room 12,151, SQLite 7,636이다. 이 벤치마크만 보면 Room이 약 1.59배 느리다. 특히 update에서 차이가 컸고, write/read/delete는 대체로 1.2~2.6배 범위다.

다만 이 자료는 최신 Room 3.x 기준이 아니다. 절대값보다 “Room 같은 추상화 계층은 hot path에서 측정 가능한 오버헤드를 만든다”는 방향성 근거로 쓰는 편이 맞다.

Jetpack Benchmark 기반 비교

2020년 Jetpack Benchmark 기반 비교는 SQLite, Room 2.2.5, DBFlow, GreenDao, Realm, ObjectBox를 같은 코드베이스와 데이터셋으로 측정했다. Pixel 2 / Android Q, airplane mode, sustained performance mode, Android Test Orchestrator 조건에서 10k~50k city dataset을 사용했고 총 17,640개 측정을 수행했다.

결론은 단순하지 않다.

작업Room 위치SQLite 위치
CreateRoom은 하위권SQLite는 2위
ReadRoom이 SQLite보다 높게 측정SQLite는 중하위
UpdateSQLite가 Room보다 높게 측정SQLite는 3위
DeleteRoom이 SQLite보다 높게 측정SQLite는 최하위
OverallRoom과 SQLite가 동률권Room과 SQLite가 동률권

이 벤치마크는 방법론이 더 현대적이고 통제가 강하지만, Room vs SQLite만 isolated microbenchmark로 본 자료는 아니다. 메시지는 “직접 SQLite가 항상 모든 작업에서 압도적으로 빠르다”가 아니라, 작업 유형과 구현 방식에 따라 차이가 달라진다는 쪽에 가깝다. 일반 CRUD 앱 워크로드에서는 Room도 충분히 경쟁 가능하다.

AndroidX benchmark source

AndroidX 소스에는 Room driver benchmark와 SQLite driver benchmark가 존재한다. Room 쪽은 small 25개, large 1000개 데이터셋, read/write/concurrent read-write를 BenchmarkRule로 측정하며 Android driver, bundled driver 등을 파라미터화한다. SQLite driver benchmark도 AndroidSQLiteDriver/BundledSQLiteDriver를 대상으로 WAL, synchronous NORMAL, small/large read/write를 다룬다.

이 자료의 의미는 최신 AndroidX가 어떤 워크로드를 중요하게 보고 benchmark하는지 보여준다는 데 있다. 다만 공개 문서 형태로 “Room 3.x가 직접 SQLite보다 몇 % 느리다” 같은 공식 최신 숫자를 제공하지는 않는다.

성능 분석

읽기

직접 SQLite는 Cursor나 prepared statement를 직접 다루므로 필요한 row를 streaming하고 필요한 column만 읽는 식으로 최적화하기 쉽다. Room은 DAO 반환 타입에 맞춰 entity, POJO, List, Flow 등을 구성하므로 객체 생성과 매핑 비용이 붙는다.

Room의 읽기 오버헤드가 커지는 조건은 다음이다.

조건이유
대량 row를 List<Entity>로 반환모든 row를 객체로 materialize하고 heap/GC 부담 증가
일부 column만 필요한데 entity 전체 조회I/O, Cursor read, 객체 필드 할당 증가
Flow<List<T>>로 큰 목록을 자주 재방출invalidation 후 list 재생성 비용 증가
type converter가 많은 schema변환 CPU 비용 증가
작은 query를 매우 고빈도로 실행SQLite 실행시간보다 Room call/mapping overhead 비중 증가

작은 화면 단위 CRUD, 설정값, 캐시, 일반 목록 조회는 Room으로 충분한 경우가 많다. 반대로 수십만 row 이상, 검색/분석성 쿼리, telemetry ingestion, sync engine, low-latency cache는 직접 SQLite 또는 Room + raw query/hot path 분리가 낫다.

쓰기

쓰기 성능은 Room 여부보다 transaction 사용 여부가 더 크게 좌우한다. SQLite는 한 번에 하나의 write transaction만 처리한다. 여러 insert를 각각 commit하면 Room이든 직접 SQLite든 느려진다.

Room에서도 batch insert DAO와 transaction을 잘 쓰면 차이가 줄어든다. 반대로 row마다 DAO를 반복 호출하면 transaction overhead, method dispatch, 객체 매핑 비용이 누적된다. 직접 SQLite는 prepared statement 재사용과 transaction 직접 제어가 쉬워 bulk insert/update에서 유리하다.

업데이트와 삭제

공개 Android ORM benchmark에서는 update에서 Room과 직접 SQLite 차이가 가장 컸다. simple update 2.70배, complex update 3.73배, balanced update 3.71배다.

가능한 원인은 entity 기반 update, per-row update, invalidation tracking, index 부족, app-side filtering이다. 성능이 중요한 update는 전체 entity update보다 UPDATE table SET col = ? WHERE indexed_col = ? 형태의 명시적 SQL, batch transaction, 적절한 index가 더 중요하다.

메모리 사용량

Room의 메모리 비용은 주로 정적 오버헤드와 동적 오버헤드로 나뉜다.

구분Room직접 SQLite
정적 오버헤드generated DAO, database impl, invalidation tracker직접 작성한 helper/statement 정도
동적 오버헤드entity 객체, List, Flow emission, type conversion, coroutine 객체Cursor/statement 중심으로 낮게 유지 가능
DB 파일 주변 파일WAL 사용 시 -wal, -shm 가능WAL 사용 시 동일

직접 SQLite가 메모리에서 유리한 경우는 큰 result set을 streaming해야 하거나, 일부 column만 필요하거나, allocation/GC가 병목이거나, low-memory device를 타깃으로 할 때다.

Room에서도 완화할 수 있다. entity 전체 대신 projection DTO를 쓰고, LIMIT/OFFSET이나 Paging을 사용하고, 대량 결과를 List로 한 번에 올리지 않으며, observable query 범위를 좁히면 된다.

CPU 사용량

CPU 사용량은 대체로 다음 순서로 영향을 받는다.

우선순위CPU 비용 원인
1SQL 자체의 비용: full scan, join, sort, group by, index miss
2I/O와 journaling: WAL, checkpoint, fsync/synchronous
3row materialization: Cursor에서 객체로 변환, type conversion
4framework overhead: DAO dispatch, Coroutine, Flow, invalidation tracking

Room의 CPU 오버헤드는 주로 3번과 4번에서 생긴다. 직접 SQLite는 이 층을 더 얇게 만들 수 있다. 그러나 index가 없어 full scan이 나거나, transaction을 잘못 써 fsync가 반복되거나, 앱 코드에서 filtering/sorting을 하면 Room vs SQLite 차이보다 SQL/schema 문제가 훨씬 커진다.

Android 환경별 선택

일반 Android 앱

대부분은 Room이 기본값이다. 이유는 raw latency가 아니라 전체 품질이다.

기준우위
생산성Room
SQL 검증Room
migration 관리Room
유지보수Room
raw latency직접 SQLite
메모리 최소화직접 SQLite

Google은 Room을 SQLite 위의 abstraction으로 설명하고, boilerplate 감소, compile-time SQL verification, migration path 제공을 장점으로 제시한다. 일반 앱에서는 Room의 안정성과 유지보수 이득이 성능 손실보다 큰 경우가 많다.

대량 동기화, 캐시, 로그 저장

대량 데이터 처리에서는 Room 단독보다 hybrid가 안전하다.

워크로드권장
서버에서 수만~수십만 row syncprepared statement + transaction 중심 직접 SQLite
telemetry/log append직접 SQLite 또는 Room batch insert + WAL
local search indexFTS/SQLite 직접 튜닝
large export/import직접 SQLite
UI 표시용 CRUDRoom

Room으로 schema와 migration을 관리하면서 bulk sync, log ingestion, FTS index update, 대량 export/import만 별도 repository에서 직접 SQLite로 처리하는 구조가 현실적이다.

메인 스레드와 UX

Room은 기본적으로 main thread DB 접근을 허용하지 않는다. 이는 쿼리를 자동으로 빠르게 만드는 기능이 아니라, UI thread가 DB 작업 때문에 lock되어 ANR이 나는 일을 막는 안전장치다.

Linux 환경별 선택

서버, CLI, 임베디드 Linux

일반 Linux에서는 직접 SQLite가 기준선이다. Room은 Android 중심 라이브러리였고, Linux에서 Room을 쓸 이유는 Kotlin Multiplatform으로 Android와 DB 계층을 공유하려는 경우가 아니면 약하다.

언어/환경일반 선택지
C/C++SQLite C API
Rustrusqlite, sqlx sqlite
Gomodernc/sqlite, mattn/go-sqlite3
Pythonsqlite3, APSW
Java/Kotlin JVMJDBC SQLite driver, SQLDelight, Room KMP
Nodebetter-sqlite3 등

성능, 메모리, CPU가 중요하면 prepared statement, cursor/step loop, mmap/cache/page size/WAL/checkpoint를 낮은 수준에서 제어할 수 있는 직접 바인딩 쪽이 유리하다.

Kotlin Multiplatform / Desktop Linux

Room KMP는 Android 외 플랫폼에서도 Room을 쓸 수 있게 한다. Room 3.0은 2026년 7월 1일 릴리스됐고, 패키지가 androidx.room3로 바뀌었으며 Kotlin Multiplatform 중심으로 재정리됐다. SQLiteDriver API 기반으로 이동하고 KSP/Kotlin codegen 및 Coroutine API 중심으로 바뀐 점도 중요하다.

KMP에서 Android와 Desktop/Linux의 DB 계층을 공유하고 싶다면 Room KMP는 검토할 만하다. 하지만 이 경우에도 성능 기준선은 여전히 “Room vs SQLite 엔진”이 아니라 “Room mapping layer vs 직접 SQLite driver”다.

SQLite 설정과 WAL

Room과 직접 SQLite 모두 SQLite 파일을 쓴다. 따라서 WAL, checkpoint, synchronous, index 같은 SQLite 설정은 둘 모두에 영향을 준다.

WAL은 write-ahead logging 방식으로, 읽기와 쓰기 동시성을 개선한다. 다만 write transaction은 여전히 한 번에 하나만 처리된다. WAL 사용 시 -wal, -shm 파일이 생길 수 있고, checkpoint와 WAL 파일 크기가 성능에 영향을 준다.

Android 공식 SQLite 성능 가이드는 batch transaction, 읽는 row/column 줄이기, SQLite 엔진 쪽으로 작업 밀어 넣기, schema/index 조정, EXPLAIN QUERY PLAN, Perfetto, SQLiteTime, dumpsys meminfo 사용을 권한다. 이 지점은 Room을 쓰든 직접 SQLite를 쓰든 그대로 적용된다.

근거 신뢰도

근거 유형신뢰도이 노트에서의 용도
Android/Room 공식 문서높음Room의 목적, 권장 사용, API 특성
SQLite 공식 문서높음SQLite/WAL 특성, journaling 성능 특성
AndroidX benchmark source높음AndroidX가 어떤 워크로드를 benchmark하는지 확인
Jetpack Benchmark 기반 독립 실험중상실제 Android 기기에서 상대 성능 경향 확인
오래된 ORM benchmark GitHub중간Room abstraction overhead의 정량 예시
블로그 memory/file-size 관찰중하WAL/SHM 파일 영향 참고. Room 고유 오버헤드로 단정 금지

가장 큰 한계는 Room 3.x 기준의 최신 공개 CPU/RAM/latency 벤치마크가 충분하지 않다는 점이다. 따라서 숫자는 “우리 프로젝트에서 그대로 재현될 값”이 아니라 설계 판단을 위한 근거다. 정확한 의사결정은 앱의 schema, query pattern, 데이터 크기, device tier, journaling 설정, thread model로 Jetpack Benchmark와 Perfetto를 돌려야 한다.

실무 선택 기준

Room을 선택할 조건은 다음이다.

조건이유
일반 Android 앱 CRUD생산성/안정성 이득이 성능 손실보다 큼
팀 개발SQL 검증, migration 관리가 중요
schema가 자주 변함migration path 관리 유리
UI observable data 필요Flow/LiveData/Paging 연동 편함
버그 비용이 성능 비용보다 큼타입 안정성과 검증이 유리

직접 SQLite를 선택할 조건은 다음이다.

조건이유
초대량 insert/updateprepared statement + transaction 직접 제어
very large readCursor streaming으로 메모리 절감
low-end device에서 CPU/GC 민감객체 materialization 최소화
latency tail이 중요abstraction overhead 제거
Android가 아닌 Linux 서비스/임베디드Room을 쓸 이유가 약함
SQLite 고급 기능 세밀 튜닝WAL/checkpoint/cache/pragma/FTS 직접 제어

결국 가장 현실적인 Android 아키텍처는 다음이다.

Room으로 schema, migration, 일반 DAO를 관리하고, 성능 critical path만 직접 SQL/driver 방식으로 최적화한다.

검증이 필요한 주장

  • Android ORM benchmark의 Room 12,151 vs SQLite 7,636 합산 수치는 최신 Room 3.x 기준이 아니므로 현재 앱에 그대로 적용하면 안 된다.
  • Jetpack Benchmark 기반 비교는 Room 2.2.5와 Pixel 2 / Android Q 환경의 결과다. 최신 기기, 최신 Room, 최신 SQLite driver에서는 달라질 수 있다.
  • AndroidX benchmark source는 방법론과 측정 대상 확인에는 유용하지만, 공식 최신 Room vs SQLite 결과 숫자를 제공하지 않는다.
  • Room KMP와 Room 3.0의 Linux/JVM 성능은 아직 공개 데이터가 충분하지 않다. 실제 선택 전 자체 benchmark가 필요하다.
  • WAL, synchronous, checkpoint, index, transaction 설계가 잘못되면 Room과 직접 SQLite 차이보다 SQLite 사용 방식의 문제가 더 커질 수 있다.

Source Fidelity Notes

  • Preserved key numbers: GitHub Android ORM benchmark의 Room/SQLite 작업별 수치와 Room 12,151 vs SQLite 7,636 합산, 약 1.59배 차이, update 2.70배/3.73배/3.71배, Jetpack Benchmark의 Pixel 2 / Android Q, 10k~50k city dataset, 17,640개 측정, AndroidX benchmark의 small 25개/large 1000개 데이터셋, Room 3.0 2026년 7월 1일 릴리스.
  • Preserved frameworks / models: Room vs SQLite 계층 구분, 읽기/쓰기/update/delete 성능 분석, 메모리/CPU 영향 요인, Android 일반 앱과 대량 처리 분리, Linux 직접 SQLite 기준선, KMP/Room 3.0 판단.
  • Preserved templates / checklists: 환경별 최종 판단표, 근거 신뢰도 표, Room 선택 조건, 직접 SQLite 선택 조건, 검증이 필요한 주장 목록.
  • Omitted or compressed: 원문의 반복 설명, 일부 보조 블로그 출처 해석, 공식 문서 설명 중 공개 페이지의 판단에 직접 필요하지 않은 문장을 줄였다. 원문 전체는 sources/ layer에 보존했다.
  • Omission risk: 특정 앱의 schema나 query pattern에 따른 수치 예측은 제공하지 않는다. 이 노트는 선택 기준이며, 실제 도입 전에는 프로젝트 데이터로 benchmark를 돌려야 한다.

출처 / 참고자료