SQLite의 장점은 가볍고 느슨하다는 거야. 그런데 그 느슨함은 때로 너무 조용해.

예를 들어 INTEGER라고 적어 둔 칸에 'garbage' 같은 문자열을 넣어도, 일반 SQLite 테이블은 그 값을 받아들일 수 있어. 나중에 애플리케이션 코드가 그 칸을 숫자라고 믿고 읽는 순간에야 문제가 튀어나오지.1

STRICT 테이블은 이 조용함을 줄이는 장치야. 테이블을 만들 때 마지막에 STRICT를 붙이면, SQLite가 삽입과 갱신 시점에 타입을 더 엄격하게 본다.

무엇이 달라지나

핵심은 테이블 정의가 약속이 된다는 점이야.

일반 테이블에서는 age INTEGER라고 써도 SQLite가 꽤 너그럽게 받아준다. 하지만 CREATE TABLE people (age INTEGER) STRICT;처럼 만들면, age 칸에 숫자로 저장할 수 없는 텍스트를 넣는 순간 오류가 난다.1

다만 이건 “문자열이면 무조건 거절”이라는 뜻은 아니야. '123'처럼 손실 없이 정수 123으로 바꿀 수 있는 값은 허용된다. 엄격함의 기준은 입력의 겉모양이 아니라, 선언한 타입으로 안전하게 저장할 수 있느냐에 가깝다.

두 번째 변화는 테이블을 만들 때부터 나타난다. SQLite는 원래 DATETIME, JSON, UUID, 심지어 오타처럼 보이는 타입 이름도 열 선언에 받아들일 수 있어. STRICT 테이블에서는 허용 타입이 INT, INTEGER, REAL, TEXT, BLOB, ANY로 좁아진다.2

이건 사소해 보여도 꽤 중요해. 타입 이름 오타가 런타임 데이터 버그로 흘러가기 전에, 테이블 생성 단계에서 막히기 때문이야.

유연함을 완전히 버리는 건 아니다

STRICT가 SQLite를 PostgreSQL처럼 바꿔 주는 건 아니야. 그리고 모든 칸이 반드시 하나의 좁은 타입만 가져야 한다는 뜻도 아니야.

SQLite는 ANY라는 타입을 둔다. 이 칸에는 정수, 텍스트, 실수, 바이너리 값을 그대로 넣을 수 있어. 그러니까 로그의 부가 속성이나 키-값 저장처럼 여러 모양의 값을 담아야 하는 칸은 ANY로 열어 두고, 나머지 일반 컬럼은 엄격하게 잠그는 식으로 쓸 수 있다.1

이 지점이 중요해. STRICT는 “SQLite의 유연함을 포기하라”가 아니라, 유연함이 필요한 칸과 실수로 느슨해진 칸을 구분하라는 제안에 가깝다.

문제는 새 테이블보다 기존 테이블이다

새 테이블이라면 쉽다. CREATE TABLE 끝에 STRICT를 붙이면 된다.

기존 테이블은 다르다. 이미 있는 비엄격 테이블을 ALTER TABLE 한 줄로 STRICT 테이블로 바꾸는 길은 없다. 새 STRICT 테이블을 만들고, 데이터를 복사하고, 기존 테이블을 교체해야 한다.3

그 과정에서 숨어 있던 문제가 드러난다. 숫자 칸에 텍스트가 들어 있거나, 선언과 실제 값이 어긋나 있으면 복사 중에 오류가 날 수 있어. 이때는 데이터를 먼저 정리하거나, 필요한 경우 CAST로 형 변환을 해야 한다.

그래서 이 기능은 “나중에 켜면 되지”보다 “처음 만들 때 켜는 게 싸다”에 가깝다. 데이터가 쌓인 뒤에는 엄격함 자체보다 기존 데이터의 청소 비용이 더 큰 일이 된다.

성능 이야기는 아직 작다

타입을 검사하니 이론적으로는 삽입과 갱신이 느려질 수 있어. 하지만 원문이 소개한 비공식 실험에서는 100개 열을 가진 테이블에 수백만 행을 넣어도 뚜렷한 성능 차이나 파일 크기 차이가 보이지 않았다고 한다.4

이건 “성능 비용이 없다”는 결론은 아니야. 벤치마크가 철저하다고 말하기는 어렵고, 쓰기 패턴과 데이터 모양에 따라 달라질 수 있다.

그래도 읽을 포인트는 있어. STRICT의 주된 비용은 CPU 몇 퍼센트보다 운영 습관에 있다. SQLite 3.37.0 이상에서만 지원되고, 더 오래된 SQLite는 STRICT 테이블이 들어간 데이터베이스를 열지 못할 수 있다.5

그러니까 배포 환경의 SQLite 버전이 제각각인 앱이라면 먼저 호환성을 봐야 한다.

다음에 볼 것

내가 이 글에서 가져갈 문장은 하나야.

SQLite의 느슨한 타입은 장점이지만, 일반적인 애플리케이션 테이블에서는 기본값으로 두기엔 너무 조용할 수 있다.

새 테이블을 만들 때는 STRICT를 먼저 검토하는 쪽이 낫다. 반대로 기존 데이터베이스를 옮길 때는 “STRICT를 켤까”보다 “이미 들어간 값들이 선언한 타입과 얼마나 어긋나 있나”를 먼저 봐야 한다.

그리고 SQLite가 왜 여전히 유연한 타입을 기본값으로 두는지도 따로 볼 문제야. 하위 호환성과 애플리케이션 파일 포맷이라는 SQLite의 역사까지 들어가면, 이건 단순히 “엄격한 게 무조건 좋다”로 끝나는 이야기가 아니거든.

각주

  1. SQLite, “STRICT Tables” 문서. ↩︎ ↩︎2 ↩︎3

  2. SQLite, “Datatypes In SQLite” 문서. ↩︎

  3. Evan Hahn, “Prefer STRICT tables in SQLite” 원문. ↩︎

  4. GeekNews, 「SQLite에서는 STRICT 테이블을 우선 사용하라」(2026-07-12) 요약. ↩︎

  5. SQLite, “SQLite Release 3.37.0” (2021-11-27) 릴리스 노트. ↩︎