- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다 지금 보는 글
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run
셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다
GAS에서 느린 건 자바스크립트가 아니라 Sheets·Drive 같은 서비스 호출이다. 루프 안 getValue/setValue를 일괄 getValues/setValues로 바꾸면 수십 배 빨라진다.
GAS 성능의 1순위 규칙: 서비스 호출 횟수를 줄여라. 느린 건 메모리 안 자바스크립트 연산이 아니라, getValue()·setValue()·appendRow() 같은 Sheets/Drive/UrlFetch 서비스 호출이다. 루프 안에서 이걸 반복하면 호출마다 왕복 비용이 쌓인다.
왜 중요한가
셀을 한 칸씩 1,000번 읽는 코드와, 한 번에 읽어 메모리에서 처리하는 코드는 체감 속도가 수십 배 차이 난다. 느린 스크립트는 6분 한도에도 더 빨리 부딪힌다. 비용은 “기다림”과 “중간에 끊김” 둘 다다.
정답: 한 번에 읽고, 메모리에서 처리하고, 한 번에 쓴다
// 나쁨: 행마다 두 번씩 서비스 호출
for (let row = 2; row <= lastRow; row++) {
const v = sheet.getRange(row, 1).getValue();
sheet.getRange(row, 2).setValue(transform(v));
}
// 좋음: 호출 2번 (읽기 1 + 쓰기 1)
function updateRows() {
const sheet = SpreadsheetApp.getActive().getSheetByName("Data");
const values = sheet.getRange(2, 1, sheet.getLastRow() - 1, 2).getValues();
const next = values.map(([input]) => [input, transform(input)]);
sheet.getRange(2, 1, next.length, 2).setValues(next);
}
같은 원칙의 다른 적용
- 외부 HTTP: 서로 독립적인 호출은
UrlFetchApp.fetchAll()로 한 번에. 단 부분 실패를{ ok, status, body, error }로 정규화하고, 일시적 실패만 백오프로 재시도한다. - 자주 읽는 값: 잘 안 바뀌는 외부 응답·마스터 데이터는
CacheService에 TTL을 두고 캐싱한다(키 100KB 한계, 넘으면 분할). - 시트 구조 변경: 서식·검증·열너비처럼 구조를 많이 바꾸면 셀 값 API가 아니라 Advanced Sheets API의
batchUpdate로 한 번에 반영한다.
깊이: UI도 같다
google.script.run 호출을 화면에서 자주 반복하면 라이브러리 로딩 비용이 체감된다. UI-heavy 앱은 라이브러리 의존을 줄이고, 데이터는 껍데기를 먼저 그린 뒤 비동기로 한 번에 가져온다.
핵심 한 줄: 루프 밖으로 서비스 호출을 빼라. 빠르기는 거기서 결정된다.
자주 묻는 질문
- GAS 스크립트가 느린 진짜 원인은 무엇인가요?
- 메모리 안 자바스크립트 연산이 아니라 getValue·setValue·appendRow 같은 Sheets/Drive/UrlFetch 서비스 호출이 원인입니다. 루프 안에서 반복하면 호출마다 왕복 비용이 쌓입니다.
- getValues/setValues로 바꾸면 얼마나 빨라지나요?
- 셀을 한 칸씩 1,000번 읽는 방식과 한 번에 읽어 메모리에서 처리하는 방식은 체감 속도가 수십 배 차이 납니다.
- 독립적인 외부 HTTP 요청을 빠르게 처리하려면 어떻게 해야 하나요?
- UrlFetchApp.fetchAll()로 한 번에 묶어 보내고, 부분 실패는 응답 배열을 요청 순서로 매핑해 처리합니다.
- 2026.07.29 Apps Script 프로젝트가 늘어나면 반드시 망가지는 것들
- 2026.07.16 매일 돌던 Apps Script 트리거가 갑자기 멈추는 이유
- 2026.07.15 브라우저 저장소에 고객정보 넣으면 생기는 문제
- 2026.07.07 브라우저가 내 데이터를 버릴 때: 초록 체크가 거짓말을 한다
- 2026.07.07 설치됨 ≠ 작동함: 백업 트리거가 한 번도 안 돌았다
- 2026.07.07 GAS엔 점진 배포가 없다: '맞는' 검사 하나가 전 사용자를 잠근다
- 2026.07.07 시트가 텍스트를 날짜로 바꾼다: '2026-06'이 완료를 영영 막을 때
- 2026.06.18 여러 사람이 한 시트에 쓰는 점검 앱: 동시성·중복·내보내기 설계
- 2026.06.12 셀을 한 칸씩 읽지 마라: 서비스 호출이 진짜 비용이다 지금 보는 글
- 2026.06.11 시트 셀에 JSON·이미지를 통째로 넣으면 터진다
- 2026.06.10 웹앱 배포 설정 하나가 보안 모델을 정한다: Execute as / 접근 권한
- 2026.06.09 GAS 6분 실행 한도: 멈추기 전에 끊어서 재개하라
- 2026.06.08 PropertiesService는 데이터베이스가 아니다: 9KB의 벽
- 2026.06.07 모바일에서 화면을 이미지로 저장할 때 멈추는 진짜 이유
- 2026.06.06 동시에 같은 시트를 쓰면 깨진다: LockService와 30 동시 실행 천장
- 2026.06.05 재배포할 때마다 주소가 바뀌면 안 된다: /exec URL 고정
- 2026.06.04 외부 호출은 가끔 실패한다: 지수 백오프와 재시도 예산
- 2026.06.03 HtmlService 앱은 껍데기 먼저: 비동기 로드와 모바일 뒤로가기
- 2026.06.02 GAS를 졸업해야 할 때: 한계 신호와 외부 DB 이전
- 2026.06.01 GAS에 지능과 엔진룸을 더하기: Vertex AI와 Cloud Run