파일 대신 SQLite 쓰기

최근에 홍민희님이 링크한 sqlite는 fopen()대신이다란 글이 있다.1 최근에 모 개발 중인 서버에서 시작시점에 데이터 파일 읽는 부분을 SQLite로 바꿔봤다.

원래의 구현은 엑셀 파일(.xls)을 서버 시작시점에 읽어서 특정 시트를 각 시트에 맞는 데이터 타입으로 바꿔서 저장하는 것. 이를 위해 Microsoft Office용 일부 dll (MS Visual Studio 2010 Tools for Office Runtime, AccessDatabaseEngine_x64)을 필요로 함. 이걸 써서 OLE로 값을 읽는다. 그리고 좀 엄하게도(…) 일부 셀은 리스트, 그것도 구조체 비슷한 것의 리스트를 적당한 토큰으로 구분해놨다. 이 부분은 문자열로 읽고 정규 표현식으로 분리해서 메모리에 올린다.

개인적으로 이 구현은 굉장히 맘에 안들었다. 문제라고 생각하는 부분은 두 가지. 일단 속도. 백 개 정도의 테스트 케이스를 실행하면 140초쯤 걸린다. 교체 대상인 내 Q8400에서 약 140초쯤 걸림. 물론 콘솔 출력을 날려버리면 (> nul) 8x ~ 9x초 수준까진 줄어든다. 느린 부분이,

  • OLE로 데이터 가져오는 부분(700ms)
  • regex 로 데이터 언마셜링하는 부분(500ms).

물론 기능 테스트에서만 전체 데이터를 로드하는 거지만 전체 테스트가 느려지는 건 스트레스.  그리고 60% 이상의 케이스가 기능 테스트이고, 이 때마다 서버 런타임 전체를 초기화 하기 때문에 여기 들어가는 시간이 매우 스트레스였다. 일단 OLE에서 데이터 읽는 부분은 처음 읽을 때만 사용하고, 이 때 데이터를 텍스트 형태로 메모리에 올린 후, 그 이후 테스트 케이스에선 이걸 읽게 했더니 꽤 빨라지긴 했지만(140초->100초) 여전히 남은 정규 표현식 Orz. 그리고 이건 데이터 늘어나면 더 느려질게 뻔하니.

두 번째는 외부 의존성. 서비스하기 위해 추가로 설치해야 하는 외부 프로그램이 있는게 맘에 들지 않는다.

그래서 (a) SQLite 테이블로 바꾸는 스크립트, (b) SQLite 테이블에서 데이터 읽는 코드 이렇게 두 가지를 만들었다.

우선 엑셀 파일(.xls)로 되어있는 데이터를 SQLite 테이블로 변환하는 코드를 작성했다. python xlrd 팩키지로 특정 시트를 읽고 여기 있는 첫 번째 행에 있는 데이터를 열 이름으로 처리하고 나머지 행에서 셀 데이터 타입을 받은 후 여기서 빈 셀이 아닌 것의 주요 타입을 열 타입으로 고름. 다만 정수/실수 선택은 적당히 실제 셀 값을 뒤져서 골랐다. 근데 SQLite에 문자열로 넣고 실행시간에 select한 후 읽는 쪽에서 고르는 게 나을지도 모르겠다. 이 테이블에 개별 행을 하나 씩 읽어서 삽입.  (INSERT ?, ?, … , args)로 끝.

마지막으로 이전에 정규 표현식으로 처리하던 부분을 python에서 해석하는 단계에서 별도 테이블을 생성하게 바꿨다. 나중에 유효성 검사할 걸 생각하면 역시 단계가 하나 더 있어야 하고, 이걸 여러 번 할 이유가 없거든…

SQLite에서 데이터 읽는 부분은 흔히 하는 sqlite3 open, prepare(SELECT 구문), 데이터 다 나올 때 까지 step k번으로 해결. OLE로 읽는 거 보다 당연히 빠르고 텍스트로 캐싱한 것 읽는 거보다 조금 늦은 수준으로 끝나더라.

이제 외부 의존성은 없고(sqlite.c가 추가되지만) 테스트 케이스 실행은 50초 수준까지 줄었다. nul로 콘솔 출력 보내면 20초 미만…

여하튼 이거 오늘 git에서 메인 스트림으로 보내버리고 딴 버그 잡고나니 하루가 지나가긴 했다. (상당 수의 작업은 금요일에 했음)


  1. 링크에 적어놓은 말 자체는 Hacker News 페이지의 제목이고, 실제로 연결된 페이지는 SQLite 사이트의 화이트 페이퍼 페이지다. ↩︎