원클릭으로
sqlite
SQLite 데이터베이스 가이드. TypeORM/Prisma 등 ORM 사용 시 알아야 할 SQLite 특성, 마이그레이션 제한사항, 동시성 처리, 성능 최적화 참조. .db, .sqlite 파일 작업 시 자동 적용.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
SQLite 데이터베이스 가이드. TypeORM/Prisma 등 ORM 사용 시 알아야 할 SQLite 특성, 마이그레이션 제한사항, 동시성 처리, 성능 최적화 참조. .db, .sqlite 파일 작업 시 자동 적용.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
GitHub PR URL을 인자로 받아 merge conflict(병합 충돌) 유무를 판정하고, 충돌이 없으면 즉시 종료한다. 충돌이 있으면 충돌 파일/원인 커밋을 추적해 어떤 PR/브랜치에서 유입된 변경인지 식별한 뒤, 양쪽 PR/이슈의 plans(또는 docs/plan) 문서를 찾아 의도한 구현을 모두 보존하는 형태로 충돌을 해결하고 commit+push 해서 PR이 다시 mergeable 해질 때까지 확인한다. PR 병합 충돌 해결을 요청받으면 사용한다.
GitHub PR URL을 인자로 받아 현재 브랜치가 PR의 head branch와 일치하는지 검증한 뒤, GitHub Actions CI 실패 원인을 분석/수정하고 commit+push 후 CI 성공을 폴링으로 확인하는 복구 루프를 수행한다. CodeRabbit/Copilot 같은 코드리뷰 체크는 제외하고 GitHub Actions run만 대상으로 한다. PR CI 실패 복구를 요청받으면 사용한다.
변경사항 커밋/푸시 워크플로우 자동화. 이슈 생성, 브랜치 생성, 원자적 커밋, 검증, push, PR 생성 후 CI 폴링/실패 복구까지 한 번에 진행해 달라는 명시적 요청에서 사용한다.
버그 상황과 로그를 받아 재현을 최우선으로 수행하고, git 변경/프로젝트 문서 기반 원인 가설을 반복 검증해 해결한다. 방향 변경이 필요하면 사용자 승인 후 진행한다.
구현 계획 문서를 6가지 관점으로 순차 리뷰하고, 수동 텍스트 승인 루프로 의견/승인을 받아 즉시 반영한 뒤 반복 루프를 수행한다.
GitHub 이슈 URL을 인자로 받아 이슈 정보를 확인하고 git worktree 기반 작업 브랜치를 생성한 뒤 이슈 계획 문서를 만든다. 이슈 URL 기준으로 브랜치/worktree/계획 문서 초기화를 요청할 때 사용한다.
| name | sqlite |
| description | SQLite 데이터베이스 가이드. TypeORM/Prisma 등 ORM 사용 시 알아야 할 SQLite 특성, 마이그레이션 제한사항, 동시성 처리, 성능 최적화 참조. .db, .sqlite 파일 작업 시 자동 적용. |
PRAGMA journal_mode = WAL; -- 동시성 향상 (필수)
PRAGMA synchronous = NORMAL; -- 성능/안전성 균형
PRAGMA foreign_keys = ON; -- 외래키 강제 (기본값 OFF!)
PRAGMA busy_timeout = 5000; -- 잠금 대기 5초
PRAGMA cache_size = -64000; -- 64MB 캐시
TypeORM에서는
extra옵션으로 설정
매 연결마다 PRAGMA foreign_keys = ON 필요!
ORM 설정에서 반드시 활성화할 것
INTEGER 컬럼에 문자열 삽입 가능 (에러 안 남!)
해결: STRICT 테이블 사용 (SQLite 3.37.0+)
NOT NULL 명시 필요: id INTEGER PRIMARY KEY NOT NULL
Boolean: 0/1 정수로 저장
DateTime: TEXT('YYYY-MM-DD HH:MM:SS'), INTEGER(Unix timestamp), REAL(Julian day)
ASCII만 NOCASE 지원, 유니코드 대소문자 구분됨
| 작업 | 지원 | 버전 |
|---|---|---|
| 테이블 이름 변경 | ✅ | - |
| 컬럼 이름 변경 | ✅ | 3.25.0+ |
| 컬럼 추가 | ✅ | - |
| 컬럼 삭제 | ✅ | 3.35.0+ |
| 컬럼 타입 변경 | ❌ | - |
| 제약조건 추가/삭제 | ❌ | - |
| PRIMARY KEY 변경 | ❌ | - |
- PRIMARY KEY/UNIQUE 불가
- NOT NULL 시 기본값 필수
- GENERATED ALWAYS ... STORED 불가
- PRIMARY KEY 또는 UNIQUE
- 인덱스에 포함됨
- FOREIGN KEY에 사용됨
- 트리거/뷰에 참조됨
1. 새 테이블 생성
2. 데이터 복사
3. 기존 테이블 삭제
4. 새 테이블 이름 변경
5. 인덱스/트리거/뷰 재생성
TypeORM: synchronize:false 권장, 마이그레이션 직접 작성
| 상태 | 설명 |
|---|---|
| UNLOCKED | 락 없음 |
| SHARED | 읽기 중 (다중 허용) |
| RESERVED | 쓰기 예정 (단일) |
| PENDING | 쓰기 대기 (새 읽기 차단) |
| EXCLUSIVE | 쓰기 중 (단독) |
원인: 다른 연결이 락 보유 중
해결:
1. busy_timeout 설정 (PRAGMA busy_timeout = 5000)
2. WAL 모드 사용
3. 재시도 로직 구현
- 읽기/쓰기 동시 가능
- 더 빠른 성능
- 읽기가 쓰기를 차단하지 않음
- 네트워크 드라이브 미지원
- -wal, -shm 추가 파일 생성
- 100MB+ 트랜잭션은 롤백 저널이 나음
| 항목 | 기본값 | 최대값 |
|---|---|---|
| DB 크기 | - | 281 TB |
| 행 크기 | 1 GB | 2 GB |
| 컬럼 수 | 2,000 | 32,767 |
| JOIN 테이블 | - | 64 |
| ATTACH DB 수 | 10 | 125 |
| SQL 길이 | 1 GB | 1 GB |
컬럼 수: 100개 이하 (정규화 권장)
동시 연결: WAL 모드로 동시성 확보
1. 온라인 백업 API 사용 (sqlite3_backup_*)
2. VACUUM INTO 'backup.db'
3. .backup 명령 (CLI)
- 단순 파일 복사 시 쓰기 중이면 손상 가능
- WAL 모드: -wal, -shm 파일도 함께 백업 필요
- 백업 중에도 읽기/쓰기 가능 (온라인 백업)
복합 인덱스 (a, b, c)의 경우:
✅ WHERE a=? AND b=? AND c=?
✅ WHERE a=? AND b=?
✅ WHERE a=?
❌ WHERE b=? (첫 컬럼 없음)
❌ WHERE a=? OR b=? (OR 조건)
ANALYZE; -- 통계 수집
PRAGMA optimize; -- 연결 종료 전 실행
EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = ?;
-- SEARCH TABLE users USING INDEX idx_email (email=?)
:memory: -- 기본 (연결별 독립)
file::memory: -- URI 방식
file::memory:?cache=shared -- 여러 연결이 공유
- 디스크 I/O 없음 (빠름)
- 연결 종료 시 자동 정리
- 테스트 환경에 최적
// Jest/Vitest 테스트
{
type: 'sqlite',
database: ':memory:',
synchronize: true, // 테스트에서만 true
}
| 항목 | INTEGER PRIMARY KEY | + AUTOINCREMENT |
|---|---|---|
| ROWID 재사용 | ✅ 삭제된 ID 재사용 | ❌ 절대 재사용 안 함 |
| 순서 보장 | ❌ 단조증가 아닐 수 있음 | ✅ 항상 단조증가 |
| 성능 | 빠름 | 느림 (sqlite_sequence 관리) |
대부분의 경우: INTEGER PRIMARY KEY (기본값) 사용
AUTOINCREMENT 필요한 경우:
- 감사/로그 시스템 (ID 연속성 필수)
- 법규 준수 요구사항
- 삭제된 ID 재사용이 보안 문제일 때
TypeORM/Prisma는 기본적으로 INTEGER PRIMARY KEY 사용
AUTOINCREMENT가 필요하면 직접 SQL로 테이블 생성
CREATE TABLE users(
first_name TEXT,
last_name TEXT,
full_name TEXT AS (first_name || ' ' || last_name), -- VIRTUAL
email_domain TEXT AS (substr(email, instr(email,'@')+1)) STORED
);
| 구분 | VIRTUAL | STORED |
|---|---|---|
| 계산 시점 | 읽을 때 | 저장할 때 |
| 저장 공간 | 없음 | 있음 |
| ALTER TABLE ADD | ✅ 가능 | ❌ 불가 |
- 서브쿼리 불가
- 비결정 함수 불가 (random 등)
- 최소 1개 일반 컬럼 필요
- SQLite 3.31.0+ 필요
| 모드 | 설명 | 웹서버 권장 |
|---|---|---|
| Single-thread | 단일 스레드만 안전 | ❌ |
| Multi-thread | 각 스레드가 독립 연결 사용 | ⚠️ |
| Serialized | 같은 연결 공유 가능 (기본값) | ✅ |
기본값(Serialized) 사용 권장
- 연결 풀 공유 가능
- 뮤텍스로 자동 직렬화
- 복잡한 스레드 관리 불필요
UNIQUE 제약: NULL 여러 개 허용 (각각 구분)
SELECT DISTINCT: NULL은 하나로 취급
산술 연산: NULL 포함 시 결과도 NULL
SQLite/Oracle/PostgreSQL: UNIQUE에서 NULL 구분 (여러 개 허용)
MS-SQL/Informix: UNIQUE에서 NULL 하나만 허용
{
type: 'sqlite',
database: 'db.sqlite',
synchronize: false, // 프로덕션에서 false!
}
{
type: 'better-sqlite3',
prepareDatabase: (db) => {
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
db.pragma('busy_timeout = 5000');
}
}
// SQLite는 Date 타입이 없음
@Column({ type: 'text' }) // ISO8601 문자열
createdDate: string;
// 또는 timestamp
@Column({ type: 'integer' })
createdAt: number; // Unix timestamp
// 컬럼 타입 변경 시 직접 SQL 작성 필요
public async up(queryRunner: QueryRunner): Promise<void> {
// 1. 임시 테이블 생성
// 2. 데이터 복사
// 3. 원본 삭제
// 4. 이름 변경
}
| 주제 | 링크 |
|---|---|
| Quirks (함정) | https://www.sqlite.org/quirks.html |
| Pragmas (설정) | https://www.sqlite.org/pragma.html |
| DataTypes | https://www.sqlite.org/datatype3.html |
| ALTER TABLE | https://www.sqlite.org/lang_altertable.html |
| Foreign Keys | https://www.sqlite.org/foreignkeys.html |
| WAL Mode | https://www.sqlite.org/wal.html |
| Locking | https://www.sqlite.org/lockingv3.html |
| Limits | https://www.sqlite.org/limits.html |
| Query Optimizer | https://www.sqlite.org/optoverview.html |
| In-Memory DB | https://www.sqlite.org/inmemorydb.html |
| AUTOINCREMENT | https://www.sqlite.org/autoinc.html |
| Generated Columns | https://www.sqlite.org/gencol.html |
| Multi-thread | https://www.sqlite.org/threadsafe.html |
| NULL Handling | https://www.sqlite.org/nulls.html |
| STRICT Tables | https://www.sqlite.org/stricttables.html |
| Backup | https://www.sqlite.org/backup.html |