스프레드시트 공백 행 삭제, 왜 방법에 따라 속도가 10배 차이날까?
스프레드시트에서 중간중간 섞인 빈 행을 삭제하는 작업, 손으로 하면 끝도 없죠. 자동화 스크립트로 해결할 수 있지만, 같은 결과를 내는 코드라도 접근 방식에 따라 처리 속도가 극명하게 갈립니다. 시트 접근 횟수를 줄이는 것만으로도 성능을 비약적으로 개선할 수 있는 원리를 실전 예제와 함께 알아봅니다.
왜 공백 행 삭제가 문제일까요?

스프레드시트로 데이터를 관리하다 보면 예상치 못한 순간에 빈 행이 생깁니다. 사용자가 실수로 데이터를 지웠거나, 외부 시스템에서 데이터를 가져오는 과정에서 누락이 발생하거나, 필터링 작업 후 일부 행만 남기고 나머지를 지우면서 중간에 구멍이 뚫리는 경우가 대표적이죠.
문제는 이런 빈 행이 데이터 분석의 정확도를 떨어뜨린다는 점입니다. 예를 들어 판매 데이터 시트에 빈 행이 섞여 있으면, 평균 계산이나 집계 함수가 오작동할 수 있습니다. 또한 데이터베이스나 다른 도구로 내보낼 때 불필요한 레코드가 생성되어 후속 작업을 복잡하게 만들죠.
수동으로 하나씩 찾아서 지우는 방법도 있지만, 데이터가 수백 행을 넘어가면 현실적으로 불가능합니다. 빈 행이 어디 숨어 있는지 찾는 것 자체가 시간 낭비이고, 실수로 데이터가 있는 행을 지울 위험도 있죠. 이럴 때 자동화 스크립트가 빛을 발합니다.
자동화 스크립트, 어떻게 작동할까요?

스프레드시트 자동화는 마치 공장의 컨베이어 벨트와 같습니다. 원자재(데이터)가 들어오면 정해진 규칙에 따라 가공(검사 및 삭제)하고, 완성품(정리된 시트)을 내보내는 과정이죠. 이 과정을 코드로 구현하면, 사람이 수백 번 클릭할 작업을 몇 초 만에 끝낼 수 있습니다.
기본 작동 원리: 3단계 프로세스
공백 행을 자동으로 제거하는 스크립트는 기본적으로 다음 순서로 작동합니다:
- 데이터 범위 파악: 시트의 첫 행부터 마지막 행까지 어디까지 데이터가 있는지 확인합니다.
- 공백 행 식별: 각 행의 특정 열(보통 첫 번째 열)을 검사하여 값이 비어 있는지 판단합니다.
- 삭제 실행: 빈 행으로 판정된 경우 해당 행을 시트에서 제거합니다.
간단해 보이지만, 이 3단계를 어떤 순서와 방식으로 구현하느냐에 따라 성능이 천차만별로 달라집니다. 같은 결과를 내더라도 실행 시간이 10배 이상 차이날 수 있죠.
방법 1: 위에서부터 한 줄씩 검사하기 (직관적이지만 느린 방식)

작동 방식
첫 번째 방법은 가장 직관적입니다. 마치 책을 읽듯이 첫 번째 행부터 순서대로 내려가며 각 행이 비어 있는지 확인하고, 빈 행을 발견하면 즉시 삭제하는 방식이죠.
단계별 흐름:
- 2번 행(1번 행은 보통 제목이므로 제외)부터 시작
- 해당 행의 첫 번째 셀 값을 확인
- 값이 비어 있으면 → 행 삭제 → 한 칸 뒤로 이동 (삭제 후 아래 행이 위로 올라오므로)
- 값이 있으면 → 다음 행으로 이동
- 마지막 행에 도달할 때까지 반복
왜 느릴까요?
이 방식의 문제는 시트에 접근하는 횟수입니다. 스프레드시트 자동화에서 가장 시간이 오래 걸리는 작업은 "시트에서 데이터를 읽거나 쓰는 것"입니다. 마치 하드디스크에서 파일을 여는 것처럼, 메모리에 있는 데이터를 처리하는 것보다 훨씬 느리죠.
이 방법은 행 하나를 검사할 때마다 시트에 접근합니다. 1,000개 행이 있다면 1,000번 시트를 열어봐야 하고, 빈 행을 삭제할 때마다 또 시트에 접근해야 합니다. 결과적으로 시트 접근 횟수가 수천 번에 달할 수 있습니다.
비유하자면: 슈퍼마켓에서 장을 볼 때 물건 하나를 살 때마다 계산대에 가서 계산하고, 다시 매장으로 돌아와서 다음 물건을 고르는 것과 같습니다. 비효율의 극치죠.
실제 성능
- 100개 행 기준: 약 5~10초
- 1,000개 행 기준: 약 1~2분
- 10,000개 행 기준: 10분 이상 소요 가능
방법 2: 모든 데이터를 먼저 가져온 후 아래부터 처리하기 (효율적인 방식)

작동 방식
두 번째 방법은 배치 처리(Batch Processing) 개념을 활용합니다. 공장에서 부품을 하나씩 조립하는 대신, 필요한 부품을 한꺼번에 가져와서 작업대에서 조립하는 것과 같죠.
단계별 흐름:
- 시트의 모든 데이터를 한 번에 메모리로 가져오기 (시트 접근 1회)
- 메모리에 저장된 데이터를 마지막 행부터 역순으로 검사
- 빈 행을 발견하면 삭제하지 않고 "삭제 대상 목록"에 추가
- 모든 검사가 끝나면, 삭제 대상 목록에 있는 행들을 한 번에 삭제 (시트 접근 1회)
왜 빠를까요?
이 방식의 핵심은 시트 접근 횟수를 최소화하는 것입니다. 데이터를 한 번만 읽어오고, 삭제도 한 번에 처리하므로 시트 접근이 단 2회로 줄어듭니다.
또한 아래에서부터 위로 검사하는 이유는, 행을 삭제할 때 위쪽 행 번호가 변하지 않기 때문입니다. 예를 들어 10번 행을 삭제하면 11번 행이 10번으로 올라오지만, 9번 행은 그대로 9번으로 유지되죠. 이렇게 하면 행 번호 재계산 없이 안정적으로 삭제할 수 있습니다.
비유하자면: 슈퍼마켓에서 필요한 물건을 모두 카트에 담은 후, 마지막에 계산대에서 한 번에 계산하는 것과 같습니다. 훨씬 효율적이죠.
실제 성능
- 100개 행 기준: 약 1~2초
- 1,000개 행 기준: 약 3~5초
- 10,000개 행 기준: 약 30초~1분
두 방법의 성능 비교표

| 비교 항목 | 방법 1 (순차 처리) | 방법 2 (배치 처리) |
|---|---|---|
| 시트 접근 횟수 | 행 개수 × 2~3회 | 2회 (읽기 1회 + 쓰기 1회) |
| 100개 행 처리 시간 | 5~10초 | 1~2초 |
| 1,000개 행 처리 시간 | 1~2분 | 3~5초 |
| 10,000개 행 처리 시간 | 10분 이상 | 30초~1분 |
| 코드 복잡도 | 낮음 (초보자 친화적) | 중간 (배열 개념 필요) |
| 안정성 | 행 번호 재계산 필요 | 역순 처리로 안정적 |
실전 활용 시나리오
시나리오 1: 매일 자동으로 정리하기
온라인 주문 데이터를 스프레드시트로 관리하는 쇼핑몰이 있다고 가정해봅시다. 고객이 주문을 취소하면 해당 행의 데이터가 삭제되지만, 행 자체는 남아서 빈 공간이 생깁니다.
해결 방법:
- 배치 처리 방식 스크립트를 작성
- 매일 오전 8시에 자동 실행되도록 트리거 설정
- 전날 발생한 빈 행들이 자동으로 정리됨
시나리오 2: 데이터 통합 전 전처리
여러 지점의 매출 데이터를 하나의 시트로 합칠 때, 각 지점 데이터 사이에 빈 행이 들어가는 경우가 있습니다.
해결 방법:
- 데이터 통합 후 배치 처리 스크립트 실행
- 분석 도구로 내보내기 전 깔끔하게 정리
- 집계 함수나 피벗 테이블이 정확하게 작동
시나리오 3: 사용자 입력 폼 관리
구글 폼으로 수집한 데이터를 시트에 저장할 때, 테스트 응답이나 스팸 응답을 삭제하면 빈 행이 남습니다.
해결 방법:
- 메뉴에 "공백 행 정리" 버튼 추가
- 관리자가 필요할 때 클릭 한 번으로 정리
- 실제 응답 데이터만 깔끔하게 유지
코드 작성 시 주의사항

1. 첫 번째 행(헤더) 보호하기
대부분의 스프레드시트는 첫 번째 행에 열 제목(예: "제품명", "가격", "날짜")이 있습니다. 이 행은 절대 삭제하면 안 되므로, 검사 범위를 2번 행부터 시작하도록 설정해야 합니다.
2. 배열 인덱스 주의하기
프로그래밍에서 배열은 보통 0부터 시작하지만, 스프레드시트의 행 번호는 1부터 시작합니다. 이 차이를 제대로 처리하지 않으면 엉뚱한 행이 삭제될 수 있습니다.
예시:
- 배열에서
data[0]은 시트의 1번 행 - 배열에서
data[9]는 시트의 10번 행 - 삭제 명령에는
+1을 해서 실제 행 번호로 변환 필요
3. 공백 판정 기준 명확히 하기
"빈 행"의 정의가 애매할 수 있습니다. 모든 셀이 비어야 하는지, 특정 열(예: 첫 번째 열)만 비어도 되는지 명확히 해야 합니다. 보통은 첫 번째 열(주요 식별자)이 비어 있으면 빈 행으로 간주하는 것이 안전합니다.
4. 대량 데이터 처리 시 타임아웃 대비
스크립트 실행 시간이 너무 길면(보통 6분 이상) 자동으로 중단될 수 있습니다. 수만 개 이상의 행을 처리해야 한다면, 데이터를 여러 번에 나눠서 처리하거나, 더 최적화된 알고리즘을 사용해야 합니다.
성능 최적화의 핵심 원리

스프레드시트 자동화에서 성능을 높이는 황금률은 다음과 같습니다:
원칙 1: 시트 접근 횟수를 최소화하라
시트에서 데이터를 읽거나 쓰는 작업은 메모리 연산보다 100~1000배 느립니다. 가능한 한 데이터를 한 번에 가져와서 메모리에서 처리하고, 결과를 한 번에 쓰는 방식이 효율적입니다.
원칙 2: 배치 작업을 활용하라
개별 셀을 하나씩 수정하는 대신, 여러 셀의 값을 배열로 한 번에 업데이트하면 속도가 비약적으로 향상됩니다. 마치 택배를 하나씩 보내는 것보다 한 상자에 담아 보내는 것이 빠른 것과 같은 원리입니다.
원칙 3: 불필요한 계산을 반복하지 마라
반복문 안에서 매번 동일한 값(예: 마지막 행 번호)을 계산하는 것은 낭비입니다. 변하지 않는 값은 반복문 밖에서 한 번만 계산하고 재사용하세요.
자동화를 넘어: 트리거 활용하기

스크립트를 수동으로 실행하는 것도 편리하지만, 트리거(Trigger)를 설정하면 완전 자동화가 가능합니다. 트리거는 특정 조건이 만족되면 스크립트를 자동으로 실행하는 기능입니다.
시간 기반 트리거
설정 예시:
- 매일 오전 8시에 실행
- 매주 월요일 자정에 실행
- 1시간마다 실행
활용 사례: 야간에 데이터가 업데이트되는 시스템이라면, 새벽에 자동으로 공백 행을 정리하여 아침에 출근했을 때 깔끔한 데이터를 볼 수 있습니다.
이벤트 기반 트리거
설정 예시:
- 시트가 열릴 때 실행
- 시트가 수정될 때 실행
- 폼 제출이 있을 때 실행
활용 사례: 구글 폼으로 데이터를 수집하는 경우, 새 응답이 추가될 때마다 자동으로 공백 행을 정리하여 항상 정돈된 상태를 유지할 수 있습니다.
실무에서 마주치는 함정들

함정 1: "보이는 공백"과 "진짜 공백"
셀이 비어 보여도 실제로는 공백 문자(스페이스)나 보이지 않는 문자가 들어 있을 수 있습니다. 이런 경우 단순 공백 체크로는 감지되지 않습니다.
해결책: 값을 가져온 후 앞뒤 공백을 제거하는 trim() 함수를 적용하고, 그 결과가 빈 문자열인지 확인하세요.
함정 2: 수식이 있는 "빈" 셀
셀에 수식이 있지만 결과값이 빈 문자열("")을 반환하는 경우, 육안으로는 비어 보이지만 기술적으로는 데이터가 있는 셀입니다.
해결책: 수식의 결과값을 기준으로 판단할지, 수식 자체의 존재 여부를 기준으로 판단할지 명확히 정의해야 합니다.
함정 3: 병합된 셀
셀이 병합되어 있으면 첫 번째 셀에만 값이 있고 나머지는 비어 있는 것처럼 보입니다. 이 경우 잘못된 행이 삭제될 수 있습니다.
해결책: 병합된 셀이 있는 시트에서는 공백 행 삭제 전에 병합을 해제하거나, 병합 범위를 고려한 로직을 추가해야 합니다.
핵심 정리
✅ 스프레드시트 자동화의 성능은 시트 접근 횟수에 달려 있다 - 데이터를 한 번에 가져와서 메모리에서 처리하는 배치 방식이 압도적으로 빠릅니다.
✅ 역순 처리(아래에서 위로)가 안전하다 - 행을 삭제할 때 위쪽 행 번호가 변하지 않아 안정적으로 작동합니다.
✅ 트리거를 활용하면 완전 자동화가 가능하다 - 시간 기반 또는 이벤트 기반 트리거로 사람의 개입 없이 데이터를 항상 깔끔하게 유지할 수 있습니다.
✅ 공백 판정 기준을 명확히 하라 - 모든 셀이 비어야 하는지, 특정 열만 체크할지, 수식 결과를 고려할지 사전에 정의해야 합니다.
✅ 실무에서는 예외 상황을 고려하라 - 보이지 않는 공백 문자, 수식이 있는 셀, 병합된 셀 등 예상치 못한 케이스를 처리할 수 있어야 합니다.
스프레드시트 자동화는 단순히 "귀찮은 작업을 줄이는 것"을 넘어, 데이터 품질을 높이고 실수를 방지하는 핵심 도구입니다. 같은 목표를 달성하더라도 어떤 접근 방식을 택하느냐에 따라 효율성이 극명하게 갈리므로, 성능 최적화의 원리를 이해하고 적용하는 것이 중요합니다. 오늘 소개한 배치 처리 방식을 활용하면, 수천 개의 행도 몇 초 만에 깔끔하게 정리할 수 있습니다.