dev.to

SQLite 3.54's diskused command needs a build flag sqlite3_analyzer never required

SQLite 3.54의 .diskused는 빌드 플래그가 필요합니다. sqlite3_analyzer에는 필요하지 않았습니다

SQLite 3.54는 별도 도구 sqlite3_analyzer를 대체하는 셸 명령 .diskused를 추가했습니다. 같은 데이터베이스 분석에서 평균 실행 시간이 약 2.4배 빨랐지만, SQLITE_ENABLE_DBSTAT_VTAB 없이 빌드하면 오류 없이 아무것도 출력하지 않습니다. 댓글에서는 장시간 분석이 롤백 저널 모드의 쓰기 커밋을 막을 수 있다는 점도 확인했습니다.

에디터 노트

자동 분석에서 성공 코드 0과 실제 분석 성공은 다릅니다. 자체 빌드에서 dbstat이 빠지면 .diskused는 빈 결과를 내고 정상 종료하므로, 스크립트가 종료 코드만 확인하면 데이터베이스 상태를 놓칠 수 있습니다. SQLITE_ENABLE_DBSTAT_VTAB 설정을 빌드 단계에서 관리해야 하는 이유가 여기에 있습니다. 동시성 설명은 댓글이 정확히 보완했습니다. 열린 쓰기 트랜잭션과 분석을 함께 둔 테스트는 커밋 시점의 충돌을 확인하지 못했습니다. 추가 재현에서는 롤백 저널 모드의 커밋이 실패했고 WAL 모드에서는 성공했지만, 저자의 추가 테스트는 3.53.4 기반이어서 3.54의 .diskused를 직접 검증한 결과와는 구분해야 합니다. 반면 성능 비교는 같은 데이터베이스를 사용했으며, CPU 명령어 측정치도 반복 확인했습니다. 약 2.4배의 도구 실행 시간 차이와 2.1%의 작업량 감소는 각각 해당 테스트 구성에 한정된 결과입니다.

AI 요약

SQLite 3.54.0은 별도 실행 파일인 sqlite3_analyzer를 폐기 예정으로 분류하고, 셸에 .diskused 명령을 추가했습니다. 이 명령은 dbstat 가상 테이블을 이용해 데이터베이스 페이지와 테이블별 공간 사용량을 분석합니다. 저자는 두 도구를 직접 빌드해 같은 데이터베이스에서 실행 시간을 비교하고, 새 명령의 빌드 조건과 동시성도 확인했습니다.

실행 시간과 보고서

저자는 테이블 4개와 인덱스 1개, 35만 행으로 구성된 약 20MB 데이터베이스를 만들고 두 도구를 각각 5회 실행했습니다. .diskused의 평균은 0.025초였고 sqlite3_analyzer는 0.061초였습니다. 평균 기준 약 2.4배 차이입니다. 저자는 새 명령이 이미 열려 있는 셸 연결을 쓰는 반면 기존 도구는 별도 프로세스와 연결을 시작한다는 점을 속도 차이의 일부로 설명합니다.

두 도구의 페이지 수와 페이로드 바이트, 페이지별 미사용 공간, B-tree 깊이는 확인한 범위에서 일치했습니다. .diskused 보고서는 242줄, 13KB였고 sqlite3_analyzer는 432줄, 21KB였습니다. 새 보고서는 기존 보고서의 일부 중복 집계를 줄였지만 저자가 실제로 확인한 수치는 유지했습니다.

빌드 플래그가 없으면 조용히 종료합니다

.diskused는 SQLITE_ENABLE_DBSTAT_VTAB 플래그를 켜야 사용할 수 있는 dbstat 가상 테이블에 의존합니다. sqlite.org의 공식 바이너리에는 이 플래그가 설정돼 있어 해당 바이너리 사용자는 문제를 겪지 않습니다. 반면 amalgamation인 sqlite3.c를 자체 플래그로 빌드하는 경우에는 별도로 설정해야 합니다.

저자는 -O2만 지정해 만든 셸에서 .diskused를 실행했습니다. 명령은 아무것도 출력하지 않고 종료 코드 0을 반환했습니다. SQL 함수 SELECT diskused('main');을 직접 호출하자 "no such table: dbstat" 오류가 나와 원인을 확인했습니다. 3.53.2에서 아직 없는 .diskused 명령을 실행하면 알 수 없는 명령이라는 오류를 내는 것과 달리, 3.54에서는 필요한 가상 테이블이 빠져도 성공한 것처럼 조용히 끝납니다. 따라서 이 명령을 자동화 스크립트에서 쓰는 자체 빌드 환경은 SQLITE_ENABLE_DBSTAT_VTAB 설정을 확인해야 합니다.

3.54 성능 개선 수치 검증

릴리스 노트는 3.54가 3.53보다 약 4% 빨라졌다고 설명합니다. 저자는 30만 행 삽입과 인덱스 생성, 인덱스를 이용한 조회 10만 회를 수행하는 C 프로그램으로 두 버전을 비교했습니다. 일반 실행 시간은 3.53.2가 0.554~0.602초, 3.54.0이 0.563~0.635초로 나왔습니다. 이 차이만으로는 운영체제 스케줄링과 파일 캐시 영향을 분리하기 어렵다고 보고, callgrind로 CPU 명령어 수를 측정했습니다.

3.53.2는 약 25억 5744만 개, 3.54.0은 약 25억 423만 개의 명령어를 사용했습니다. 같은 작업에서 약 2.1% 줄어든 결과입니다. 저자는 자신의 쓰기와 인덱스 생성 중심 작업에서 CPU 작업량이 줄었다는 점은 확인했지만, 4%라는 수치는 speedtest1의 다른 작업 구성에서 나온 값이라 자신의 측정으로 재현할 수 없다고 구분합니다.

동시성 테스트와 보완

저자는 쓰기 트랜잭션이 열린 상태에서 .diskused를 실행해도 차단이나 SQLITE_BUSY가 발생하지 않았다고 처음 보고했습니다. 댓글은 이 테스트가 BEGIN IMMEDIATE가 확보하는 RESERVED 잠금과 분석 중 읽기 작업의 SHARED 잠금이 공존하는 경우만 다뤘다고 지적합니다. 롤백 저널 모드에서는 쓰기 커밋에 EXCLUSIVE 잠금이 필요하므로 분석이 SHARED 잠금을 잡고 있는 동안 커밋이 대기하거나 실패할 수 있다는 설명입니다.

저자는 댓글을 반영해 dbstat 커서를 읽는 동안 쓰기를 커밋하는 경우를 추가로 시험했습니다. 0.2초 busy timeout에서 롤백 저널 모드는 BEGIN IMMEDIATE와 INSERT는 통과했지만 COMMIT이 "database is locked" 오류로 실패했습니다. WAL 모드에서는 커밋이 완료됐습니다. 다만 이 추가 테스트는 SQLite 3.53.4를 쓰는 Python sqlite3 모듈에서 수행했고, 3.54의 .diskused 명령 자체로 시험하지는 않았다고 밝혔습니다. 저자는 잠금 규칙이 버전 사이에 바뀌지 않았고 같은 dbstat 테이블을 읽으므로 동작도 같을 것으로 예상한다고 덧붙였습니다.

dev.to 반응

  • @arhancanli — 동시성 테스트는 열린 쓰기 트랜잭션만 다뤘습니다. 그 경우 RESERVED와 SHARED 잠금은 공존합니다. 달라질 수 있는 경우는 .diskused가 읽는 도중 쓰기 작업이 커밋하는 상황입니다. 롤백 저널 모드에서는 커밋에 EXCLUSIVE 잠금이 필요하고 dbstat 스캔은 페이지를 읽는 동안 SHARED 잠금을 유지하므로, 대용량 데이터베이스에서는 보고서가 끝날 때까지 쓰기 커밋이 멈출 수 있습니다. 열린 SELECT 커서를 둔 채 BEGIN IMMEDIATE, INSERT, COMMIT을 실행하는 Python 테스트에서는 0.2초 busy timeout이 COMMIT 단계에서 "database is locked"로 실패했습니다. WAL 모드에서는 읽기가 쓰기를 막지 않습니다. WAL 테스트에서도 스캔 도중 커밋을 시도했나요, 아니면 열린 트랜잭션만 확인했나요?
    • @alexgeorgiev17 — 아니요. 두 모드 모두 열린 트랜잭션만 확인했습니다. 커밋 도중 스캔하는 경우는 테스트하지 않았고, 그게 실제로 중요한 경우라는 지적이 맞습니다. 방금 dbstat 커서를 열어 둔 채 시험했습니다. 0.2초 busy timeout에서 롤백 저널 모드는 BEGIN IMMEDIATE와 INSERT는 성공했지만 COMMIT이 "database is locked"로 실패했고, WAL 모드에서는 전체 작업이 커밋됐습니다. 이 테스트는 SQLite 3.53.4를 쓰는 Python sqlite3 모듈에서 실행했고 3.54의 .diskused 명령으로 직접 시험하지는 않았습니다. 잠금 규칙은 두 버전 사이에 바뀌지 않았고 .diskused도 같은 dbstat 테이블을 읽으므로 3.54에서도 같을 것으로 예상합니다. 롤백 모드에서 대용량 데이터베이스를 분석하면 보고서가 실행되는 동안 쓰기 커밋이 막히거나 busy timeout이 더 짧을 때 실패할 수 있습니다. "아무것도 바뀌지 않았다"는 제 설명은 지나치게 단정적이었습니다. 커밋 사례와 WAL 및 롤백 저널 차이를 추가하겠습니다. 추측으로 끝내지 않고 재현해 주셔서 감사합니다.

원문: dev.to / 번역·요약: Trawling