업무자동화

엑셀 수식 분석기 만들기 ③ GB 대용량 파일을 스트리밍으로 처리하기

피노K

시트 24개, 수식 약 190만 칸짜리 xlsb 하나에서 분석이 끝나지 않았습니다. 2026년 10월 31일에 원인을 찾아 고친 뒤 읽기 67초, 분석 37초, 보고서 1초로 끝났습니다. 파일 크기 상한도 100MB에서 4GB로 올렸습니다.

합성 파일로는 몇 초 만에 끝나던 분석기였습니다. 실무 엑셀은 수백 MB가 보통이고 GB를 넘는 것도 많습니다. 수식이 백만 칸을 넘으면, 작은 파일에서는 보이지 않던 설계의 빈틈이 시간과 메모리로 드러납니다.

먼저 결론

  • 50MB대 xlsb에서 분석이 끝나지 않던 원인은 공유 수식 연결의 제곱 시간이었고, 색인과 묶음 단위 분석으로 풀었습니다.
  • 파일 크기 상한을 4GB로 올리고 시트를 조각으로 읽게 했지만, 수식 칸당 메모리는 아직 줄이지 못했습니다.
  • 진행률 막대, 결과 새 창, 흐름도 선 설명창을 붙이면서 새 창의 스크립트가 막히는 문제를 만났습니다.
  • AI가 엑셀 데이터를 통째로 넣어 만든 HTML 대시보드를 읽어 실제 구조와 작업 요청문을 만드는 기능을 추가했습니다.

54MB 파일을 멈춘 건 제곱 시간이었다

첫 실패는 파일 크기 54MB로 크지 않은 xlsb였습니다. 오류도 없고 진행 표시도 없었습니다. 멈춘 것인지 느린 것인지조차 알 수 없었습니다.

먼저 읽기와 분석 중 어느 쪽이 느린지 단계별로 시간을 쟀습니다. 읽기도 느렸지만 끝나지 않는 쪽은 분석이었습니다. 칸 수에 비례하지 않고 그 제곱으로 늘어나는 곳이 있었습니다.

xlsb의 공유·배열 수식은 첫 칸에만 원문이 있습니다. 나머지 칸에는 "저 원문을 쓴다"고만 적혀 있습니다. 분석기는 이 연결을 셀마다 전체 목록을 훑어 찾고 있었습니다.

190만 칸이면 훑는 횟수가 수조 번이 됩니다.

고친 것은 세 가지입니다. 공유 수식의 첫 행을 색인으로 만들어 바로 찾게 했습니다. 분석 단위를 셀에서 R1C1 묶음으로 바꿔, 같은 모양의 수식 수천 칸을 한 번에 다루게 했습니다. 셀 값은 종류만 남기고 열마다 2,000개 표본만 보관하게 했습니다.

결과는 읽기 67초, 분석 37초, 보고서 1초였습니다.

같이 찾은 문제도 있었습니다. 한도 초과 오류가 날 때 압축 파일을 닫지 않아 임시 사본 삭제가 실패했습니다. 그 삭제 오류가 원래 오류를 덮어 버려서 함께 고쳤습니다.

메모리는 수식 칸 수에 비례했다

다음에 만난 것은 "파일이 비어 있거나 100MB를 넘습니다"라는 문구였습니다. 상한 100MB는 첫 버전의 안전장치였는데 실제 파일 대부분이 걸렸습니다.

상한을 기본 4GB로 올리고 실행 옵션으로 더 올릴 수 있게 했습니다. 하지만 상한만 올리면 메모리가 그만큼 필요합니다.

그래서 읽는 방식을 바꿨습니다. xlsx의 시트와 문자열 표는 XML을 통째로 올리지 않고 행 단위로 읽고, 끝난 행은 바로 비웁니다. xlsb의 시트는 레코드를 조각으로 읽습니다. 셀 값 종류는 열마다 바이트 배열에 칸당 1바이트로 넣었습니다.

합성 파일로 잰 결과는 아래와 같습니다.

파일 수식 칸 시간 최대 메모리
xlsx 94MB 600만 292초 3.4GB
xlsb 111MB (같은 내용) 600만 236초 3.2GB
xlsx 283MB 1,800만 701초 8.9GB

메모리는 파일 크기가 아니라 수식 칸 수에 비례했습니다. 수식 칸 하나당 약 500바이트가 남습니다. 이 수치는 다른 작업과 CPU를 나눠 쓰는 중에 잰 것입니다.

GB 파일에 수식이 수천만 칸이면 32GB PC로도 모자랄 수 있습니다. 이 문제는 풀지 못했습니다. 메모리 부족이 나면 화면에 그 사실과 대처를 안내하는 데서 멈췄습니다. xls는 라이브러리 특성상 여전히 통째로 읽습니다.

화면 쪽에서도 하나 실패했습니다. 상한을 넘는 큰 파일을 올리면 서버가 업로드 도중 연결을 끊습니다. 그러면 브라우저가 서버의 오류 문구를 읽지 못하고 빈 오류만 보여 줬습니다.

업로드 전에 서버 상태를 먼저 물어 임시 공간과 상한을 확인하게 바꿨습니다. 분석 중에는 10초마다 공백 한 바이트를 보내 연결을 유지합니다.

새 창에서는 스크립트가 돌지 않았다

멈춘 것인지 느린 것인지 모르는 문제는 진행률로 풀었습니다. 읽기 단계는 읽은 바이트를 부품 크기 합으로 나눕니다. 분석은 네 단계로 나눠 비율을 보냅니다. 화면은 업로드 15%까지와 그 뒤의 단계 줄을 받아 막대를 그립니다.

결과 보고서는 화면 안에 끼워 넣지 않고 '결과 보기' 버튼으로 새 창에 엽니다.

흐름도에는 선이 많아 어디로 가는지 알기 어렵다는 지적이 있었습니다. 선에 마우스를 올리면 굵게 강조되고 출발·도착 설명창이 뜨게 했습니다. 상자 안 글자가 잘리던 것은 상자를 키우고 두 줄로 접어서 고쳤습니다.

새로 만든 두 번째 보고서에서 실패가 하나 있었습니다. 보고서에 체크리스트와 메모 기능을 넣었는데, 새 창에서 스크립트가 전혀 돌지 않았습니다.

저는 새 창이 원래 화면의 보안 정책을 물려받아 인라인 스크립트가 막힌다고 봤습니다. 브라우저 자동화로 확인해 보니 맞았습니다.

그래서 보고서를 브라우저 메모리에서 바로 열지 않게 바꿨습니다. 서버가 일회용 주소로 잠시 들고 있다가 보고서 전용 정책과 함께 서빙합니다. 파일로 저장해 열어도 같은 기능이 동작합니다.

AI 시연물 HTML도 거꾸로 읽을 수 있었다

마지막으로 붙인 기능은 엑셀이 아니라 HTML을 읽습니다. 요즘 엑셀을 AI에 넣으면 보기 좋은 HTML 대시보드가 바로 나옵니다. 문제는 그 HTML 안에 데이터가 통째로 박혀 있다는 것입니다. 다음 달에 데이터가 바뀌면 다시 만들어야 합니다.

그래서 시연물 HTML을 읽어 내장 데이터·화면 구역·차트·계산·박힌 숫자·외부 의존을 해부하게 했습니다. 원본 엑셀의 표와 열을 맞춰 보고, 실제로 돌아가는 구조를 세 수준으로 추천합니다.

결과물은 PRD 초안, 데이터 계약, 가짜 표본, 그리고 AI에게 그대로 줄 작업 요청문입니다.

원칙은 같습니다. HTML 안의 스크립트를 실행하지 않고, AI를 부르지 않으며, 보고서에 데이터 값을 넣지 않습니다.

검증은 합성 시연물 8종에 손으로 정답표를 만들어 대조했습니다. 종료 기준은 "생성된 요청문대로 사람이 직접 전환했을 때 원래 시연물과 같은 숫자가 나오는가"로 잡았습니다.

차트 라이브러리를 쓴 시연물 하나를 요청문대로 화면·계산·데이터·변환 네 파일로 옮겨 봤습니다. 전체와 지점별 숫자 카드·표·차트 데이터가 원래 시연물과 같았습니다. 다만 실제 업무용 시연물로는 아직 돌려 보지 못했습니다.

바꾼 것과 아직 못 한 것

바꾼 것은 분석기의 체급입니다. 수식 백만 칸대 파일이 2분 안에 끝나고, GB 파일을 받습니다. 진행률과 새 창 보고서로 기다리는 동안 상태를 알 수 있고, 엑셀 외에 AI 시연물도 읽습니다.

못 한 것은 수식 칸당 500바이트 메모리입니다. 수식 원문을 공유 수식의 원본과 위치 차이로 줄이는 설계를 문서로만 적어 두었습니다.

시연물 기능은 내장 값과 엑셀 값의 대조, 분리 사본 자동 생성, 실행 확인이 남았습니다. 이날의 변경은 아직 저장소에 커밋하지 않은 상태입니다.

합성 파일에서 잘 돌던 코드는 실제 파일의 크기 앞에서 세 번 멈췄습니다. 제곱 시간, 100MB 상한, 메모리였고, 셋 다 작은 파일에서는 보이지 않던 것이었습니다.

이 연재는 여기서 마칩니다. 다음에는 수식 묶음을 저장해 두고 읽기 전용으로 질의하는 구조를 만들면 그 작업기를 이어 쓰겠습니다.

'업무자동화' 카테고리의 다른 글