Watch at Ease세상을 읽고, 일상의 답을 찾다.

기술 · 실용 가이드

SQLite 백업 완료가 끝일까요? 교체 전에 스냅샷을 다시 열고 검증하세요

백업 호출 완료는 복사가 끝났다는 뜻일 뿐 복구 계약 충족을 보장하지 않습니다. 정확한 파일을 읽기 전용으로 다시 열고 SQLite와 앱 검사를 통과한 뒤 승격하고 이전 정상본을 교체하세요.

생성, 읽기 전용 재개방, SQLite 검사, 앱 검사, 승격과 이후 교체를 보여 주는 원본 기술 그림.
원본 기술 일러스트: 정확한 후보는 구조·외래 키·앱 검사를 통과할 때까지 후보입니다. Watch at Ease

SQLite 백업 호출 성공은 복구 승인 절차의 시작입니다. 고유한 후보 경로에 만들고 대상 연결을 닫은 뒤 그 정확한 파일을 읽기 전용으로 다시 열어 검사가 운영 DB를 보지 않도록 합니다.

승인에는 엔진 수준과 앱 수준 증거가 모두 필요합니다. 모든 검사를 통과한 뒤 대상 파일시스템에서 후보를 승격하고, 승격 파일의 재개방이 성공할 때까지 직전 정상 백업을 보존합니다.

1. 최종 교체 대상이 아닌 후보를 만드세요

원본을 계속 사용하거나 진행률과 페이지 단위 복사가 필요하면 온라인 백업 API를 사용합니다. Python에서는 Connection.backup()입니다. VACUUM INTO도 일관된 압축 스냅샷을 만들지만 출력은 새 파일이나 빈 파일이어야 하며 중단되면 불완전하거나 손상된 파일이 남을 수 있습니다.

승격할 디렉터리에 고유한 후보를 만드세요. 활성 WAL DB의 주 .db 파일만 무작정 복사하지 마세요. 파일 복사를 쓰는 절차라면 DB를 안전하게 정지하거나 필요한 동반 파일을 모두 처리해야 합니다.

2. 정확한 후보를 읽기 전용으로 다시 여세요

대상 연결을 닫고 후보 자체를 읽기 전용 URI로 여세요. 원본 연결이나 운영 DB로 해석될 수 있는 별칭 경로에서 승인 쿼리를 실행하지 마세요. 승격 전 경로, 크기, 해시, SQLite와 Python 버전, 생성 방법과 결과를 기록합니다.

CPython 3.12.14, SQLite 3.53.1 Linux 실험에서 Connection.backup() 후보는 읽기 전용으로 열렸고 승격 후 경로도 별도 단계에서 다시 열렸습니다. 이 구분은 메모리 성공 플래그가 잡지 못하는 경로 오류를 찾습니다.

3. 구조·외래 키·앱 검사를 결합하세요

PRAGMA quick_check가 ok 한 행만 반환하도록 요구하거나 시간이 허용되면 더 철저한 integrity_check를 사용하세요. 그러나 둘 다 외래 키를 검증하지 않습니다. SQLite는 integrity_check가 외래 키 오류를 찾지 않는다고 명시하므로 foreign_key_check도 실행해 빈 결과를 요구합니다.

그 다음 user_version 또는 마이그레이션 표, 필수 표와 인덱스, 알려진 센티널, 핵심 행 수나 불변식과 대표 읽기를 검사합니다. 네 행 실험은 quick_check=ok, 외래 키 행 없음, sentinel=(sentinel, 3)을 보였고 처음 16바이트를 손상한 복사본은 다시 열 때 거부됐습니다.

4. 먼저 승격하고 이전 사본은 마지막에 교체하세요

검사가 실패하면 후보를 교체 집합 밖에 두고 직전 정상 백업과 정확한 실패 쿼리를 보존하세요. 후보를 제자리에서 고쳐 승인하지 말고 새 스냅샷을 만들어 출처를 분명히 하세요. 구조 검사 성공도 업무 데이터의 완전성·최신성·의미를 보장하지 않습니다.

모두 통과하면 같은 파일시스템에서 이름 변경이나 교체로 승격합니다. Python은 os.replace가 성공 시 원자적이지만 파일시스템 사이에서는 실패할 수 있다고 설명합니다. 이전 백업을 삭제하기 전 승격 경로를 다시 열고 최소 센티널 검사를 반복하며, 별도로 격리 환경에서 전체 복구 훈련을 수행하세요.

온라인 API, VACUUM INTO, 통제된 파일 복사를 공통 승인 게이트에 연결한 원본 기술 그림.
원본 기술 일러스트: 생성 방식은 달라도 완성된 후보에는 같은 재개방 검증이 필요합니다. Watch at Ease