본문 바로가기
서버 구축·실습

GCP BigQuery에서 CSV·GCS·Google Sheets 데이터를 적재하는 방법 (실습 기반 완전 가이드)

by joe2026 2026. 3. 24.

이 글은 BigQuery 데이터 적재를 처음 수행하는 클라우드 학습자를 위한 실습 기록입니다.
문제는 CSV 파일, Google Cloud Storage, Google Sheets처럼 서로 다른 데이터 소스를 BigQuery로 어떻게 가져오고, 각각의 방식이 어떤 차이를 가지는지 처음에는 흐름이 잘 잡히지 않는다는 점입니다.
이 글을 통해 BigQuery에서 CSV 업로드, GCS 데이터 적재, Google Sheets 외부 테이블 연결까지 전체 과정을 직접 따라할 수 있습니다.

이 글의 핵심 질문
BigQuery에서 다양한 데이터 소스를 테이블로 적재하고 활용하려면 어떻게 해야 하는가?


실습 환경

  • Cloud: Google Cloud Platform
  • 서비스: BigQuery
  • 데이터 소스: Local CSV, Google Cloud Storage, Google Sheets
  • Dataset: ecommerce
  • Table: products, products_comments
  • 적재 방식: 내부 테이블 + 외부 테이블

아키텍처

이번 실습은 단순히 파일 하나를 업로드하는 수준이 아닙니다. 로컬 CSV 파일을 BigQuery에 적재하고, 같은 데이터를 GCS 경로를 통해 다시 적재하며, 마지막에는 Google Sheets를 외부 테이블로 연결해 협업 데이터까지 조회하는 흐름입니다.

Local CSV → BigQuery products → Google Cloud Storage 재적재 → Google Sheets 협업 → External Table products_comments


전체 흐름

이번 실습은 크게 5단계로 진행됩니다.

  1. Dataset 생성
  2. 로컬 CSV 파일을 BigQuery 테이블로 적재
  3. Google Cloud Storage 경로에서 같은 데이터 재적재
  4. 재고 회전 비율 계산용 SQL 실행
  5. Google Sheets를 외부 테이블로 연결해 코멘트 데이터 조회

즉, 이번 글의 핵심은 “파일 적재”가 아니라 데이터 소스별 적재 방식과 활용 차이를 이해하는 것입니다.


■ 강사 설명

실습 시나리오는 전자상거래 운영팀과 마케팅팀이 함께 쓰는 데이터 환경을 만드는 것입니다. 기존 거래 데이터에는 재고 수준이나 리뷰 기반 감성 데이터가 없기 때문에, 별도로 제공된 제품 재고 데이터와 협업용 코멘트 데이터를 BigQuery에 연결해 분석 가능하게 만드는 것이 목표입니다.

특히 실습은 로컬 CSV 업로드와 GCS 적재, 그리고 Google Sheets 외부 테이블을 모두 다루므로, BigQuery를 단순 저장소가 아니라 데이터 허브처럼 활용하는 흐름을 배울 수 있습니다.


■ 내가 이해한 핵심

이번 실습의 본질은 아주 분명합니다.

분석은 데이터를 모은 뒤에 시작된다

BigQuery에서 SQL을 잘 작성하더라도 필요한 데이터가 테이블에 없으면 아무것도 할 수 없습니다. 반대로 데이터를 하나로 모아두면 운영팀 재고 데이터, 마케팅 분석 데이터, 협업용 메모 데이터까지 한 플랫폼에서 다룰 수 있습니다.


■ 내가 실제로 겪은 문제

가장 먼저 부딪힌 문제는 GCS 데이터를 다시 적재하는 단계에서 발생한 에러였습니다. 이유는 단순했습니다.

이미 같은 이름의 테이블 ecommerce.products가 존재했기 때문입니다.

처음에는 “왜 같은 파일인데 안 들어가지?”라고 생각하기 쉽지만, BigQuery는 기본적으로 기존 테이블을 자동 덮어쓰지 않습니다. 즉, 적재 작업에서는 데이터 자체보다도 쓰기 방식(Write Preference)을 이해하는 것이 중요합니다.


실습 단계

1단계. 데이터를 저장할 Dataset 생성

목적: 앞으로 적재할 테이블을 담을 논리적 공간을 먼저 만드는 단계입니다.

BigQuery 콘솔에서 현재 프로젝트 오른쪽의 점 3개 메뉴를 클릭한 뒤 Create Dataset을 선택합니다. Dataset ID는 ecommerce로 지정하고, 나머지 옵션은 기본값으로 둡니다. 생성이 완료되면 프로젝트 아래에 ecommerce 데이터셋이 표시됩니다. :contentReference[oaicite:0]{index=0}

이 단계는 단순한 생성처럼 보이지만 중요합니다. BigQuery에서 Dataset은 폴더와 비슷한 개념이기 때문입니다. 이후 생성할 products, products_comments 같은 테이블은 모두 이 Dataset 안에 들어가게 됩니다. 실무에서도 Dataset 이름을 잘 잡아야 이후 관리가 쉬워집니다.


2단계. 로컬 CSV 파일을 BigQuery 테이블로 적재

목적: 로컬에 있는 제품 재고 파일을 BigQuery 내부 테이블로 적재하는 단계입니다.

먼저 제품 재고 CSV 파일을 로컬 컴퓨터에 다운로드합니다. 실습에서는 products.csv 파일을 사용합니다. 그 다음 BigQuery에서 ecommerce Dataset을 선택하고 Create Table을 클릭합니다.

설정은 다음과 같이 잡습니다.

  • Create table from: Upload
  • Select file: 방금 다운로드한 products.csv
  • File format: CSV
  • Table name: products
  • Schema: Auto Detect

Partition과 Cluster 설정은 기본값으로 두고, Advanced Options도 그대로 둡니다. 이후 Create Table을 누르면 products 테이블이 생성됩니다. :contentReference[oaicite:1]{index=1}

여기서 중요한 개념은 Auto Detect입니다. CSV는 본질적으로 타입 정보가 없는 텍스트 파일이기 때문에, BigQuery가 컬럼 구조를 자동으로 추론해주는 기능이 매우 중요합니다. 물론 실무에서는 명시적 스키마를 쓰는 경우도 많지만, 초반 실습에서는 Auto Detect로도 충분히 흐름을 이해할 수 있습니다.

생성 후에는 Preview 탭에서 컬럼들이 제대로 들어왔는지 확인합니다. 실습 문서 예시에는 다음과 같은 컬럼이 보입니다.

  • SKU
  • name
  • orderedQuantity
  • stockLevel
  • restockingLeadTime

즉, 제품명과 재고 수준, 발주 리드타임까지 한 번에 볼 수 있는 구조입니다. Preview를 확인하는 이유는 단순히 “들어갔다”를 확인하는 것이 아니라, 컬럼 분리가 깨지지 않았는지, header가 잘못 데이터로 들어가지 않았는지, 숫자 컬럼이 문자열로 잡히지 않았는지 점검하기 위해서입니다.


3단계. 적재된 products 테이블을 SQL로 빠르게 검증

목적: 적재가 성공했는지, 그리고 데이터가 분석 가능한 상태인지 확인하는 단계입니다.

적재가 끝났다고 바로 믿지 말고, SQL로 한 번 검증하는 습관이 중요합니다. 실습에서는 가장 기본적인 쿼리로 재고가 높은 상품 상위 5개를 조회합니다.

#standardSQL
SELECT
 *
FROM
 ecommerce.products
ORDER BY
 stockLevel DESC
LIMIT 5

이 쿼리의 목적은 단순합니다. 데이터가 실제로 products 테이블에 들어와 있는지, stockLevel이 숫자형으로 제대로 정렬되는지, 상품명이 예상대로 보이는지를 한 번에 확인하는 것입니다. 실습에서는 재고 수준이 매우 높은 상품들이 결과로 표시되며, 이 과정에서 같은 상품명이 다른 SKU로 나올 수 있다는 점도 자연스럽게 확인하게 됩니다. :contentReference[oaicite:2]{index=2}

여기서 얻는 중요한 통찰은 하나입니다. 상품명은 같아도 SKU가 다를 수 있다는 점입니다. 즉, 색상이나 옵션이 다른 같은 상품이 서로 다른 SKU로 존재할 수 있습니다. 그래서 분석 기준을 이름(name)으로 볼지 SKU로 볼지에 따라 결과가 달라질 수 있습니다.


4단계. Google Cloud Storage에서 같은 파일을 다시 적재해 보기

목적: 로컬 업로드와 GCS 경로 적재의 차이를 이해하는 단계입니다.

이제 같은 데이터를 이번에는 로컬이 아니라 Google Cloud Storage 경로에서 적재해 봅니다. 다시 ecommerce Dataset에서 Create Table을 클릭하고, 다음처럼 설정합니다.

  • Create table from: Google Cloud Storage
  • Select file from GCS bucket: cloud-training/data-insights-course/exports/products.csv
  • File format: CSV
  • Table name: products
  • Schema: Auto Detect

여기서 바로 에러가 발생합니다. 이유는 이미 ecommerce.products라는 테이블이 존재하기 때문입니다. BigQuery는 기본적으로 동일 테이블명 덮어쓰기를 자동 허용하지 않습니다. 실습 문서도 이 점을 문제로 제시하고, 해결 방법으로 Project History에서 해당 에러 작업을 선택한 뒤 Repeat load job을 누르고, Advanced Options에서 Write Preference → Overwrite table을 선택하라고 안내합니다. :contentReference[oaicite:3]{index=3}

이 단계는 매우 중요합니다. 초보자는 종종 “같은 이름이면 그냥 덮어쓰겠지”라고 생각하지만, 실제 데이터 플랫폼은 그렇게 동작하면 위험합니다. 실수로 기존 데이터를 날릴 수 있기 때문입니다. 그래서 BigQuery는 쓰기 정책을 명시적으로 요구합니다.

즉, 이 단계에서 배워야 할 핵심은 단순히 GCS에서 데이터를 읽는 것이 아니라 BigQuery 적재 작업은 쓰기 정책까지 포함해 이해해야 한다는 점입니다.


5단계. 재고 회전 비율을 계산하는 SQL 실행

목적: 적재된 데이터를 실제 운영 의사결정에 사용할 수 있는지 확인하는 단계입니다.

이제 products 테이블을 기반으로 “어떤 상품이 재고 부족 위험이 큰가?”를 계산합니다. 실습 문서에서는 orderedQuantity와 stockLevel을 나누어 ratio를 만들고, 재고가 80% 이상 소진된 상품만 걸러서 리드타임이 긴 순으로 정렬하는 쿼리를 제시합니다.

#standardSQL
SELECT
 *,
 SAFE_DIVIDE(orderedQuantity,stockLevel) AS ratio
FROM
 ecommerce.products
WHERE
 orderedQuantity > 0
 AND SAFE_DIVIDE(orderedQuantity,stockLevel) >= .8
ORDER BY
 restockingLeadTime DESC

여기서 SAFE_DIVIDE를 쓴 이유는 분모가 0일 수 있는 상황에서 에러를 방지하기 위해서입니다. 즉, 실무형 SQL에서는 단순 나누기보다 예외 상황까지 고려한 함수 선택이 중요합니다.

이 쿼리의 결과는 운영 의사결정과 바로 연결됩니다. 예를 들어 현재 재고 대비 주문량 비율이 95% 수준인데, 재입고 리드타임이 45일이라면 해당 상품은 프로모션보다 발주 우선 검토 대상일 수 있습니다. 실습 문서도 이런 식으로 특정 상품이 높은 ratio와 긴 restockingLeadTime을 가진다고 설명합니다. :contentReference[oaicite:4]{index=4}

즉, 이 단계는 단순 분석이 아니라 적재한 데이터를 실제 판단 기준으로 바꾸는 첫 단계입니다.


6단계. BigQuery 결과를 Google Sheets로 저장해 협업용 데이터 만들기

목적: 분석 결과를 사람이 수정 가능한 협업 문서로 전환하는 단계입니다.

이제 Query Results에서 Save Results → Google Sheets를 선택합니다. 팝업이 뜨면 Open을 눌러 새 시트를 엽니다. 실습에서는 이 시트의 G열에 comments라는 새 컬럼을 추가하고, 첫 번째 상품 행에 new shipment on the way 같은 코멘트를 입력하도록 안내합니다. :contentReference[oaicite:5]{index=5}

이 단계가 중요한 이유는 BigQuery는 분석에는 강하지만, 현업 실무자의 간단한 수기 메모나 상태 업데이트에는 Google Sheets가 훨씬 편하기 때문입니다. 즉, 이 단계는 분석 시스템과 협업 시스템을 연결하는 과정입니다.

그 후 Google Sheets의 공유 가능한 링크를 복사합니다. 이제 이 스프레드시트를 BigQuery에서 외부 테이블로 연결할 준비가 된 것입니다.


7단계. Google Sheets를 BigQuery 외부 테이블로 연결

목적: 시트의 데이터를 BigQuery 안으로 복사하지 않고, 연결된 상태로 조회하는 단계입니다.

다시 ecommerce Dataset에서 Create Table을 클릭한 뒤, Source를 Drive로 선택합니다. Select Drive URI에는 방금 복사한 스프레드시트 URL을 넣습니다. File format은 Google Sheet, Table type은 기본값인 External table, Table name은 products_comments로 지정합니다.

Schema는 Auto Detect를 선택하고, Advanced options에서는 Header rows to skip = 1로 설정합니다. 즉, 첫 번째 행은 컬럼명으로 보고 실제 데이터에서는 제외하겠다는 의미입니다. 이후 Create Table을 누르면 외부 테이블이 생성됩니다. :contentReference[oaicite:6]{index=6}

여기서 반드시 이해해야 할 점은 외부 테이블은 “적재(load)”가 아니라 “연결(link)”이라는 것입니다. 실습 문서도 이 경우에는 load job이 생성되지 않는다고 분명히 설명합니다. 왜냐하면 데이터가 BigQuery 내부 저장소로 복사된 것이 아니기 때문입니다. :contentReference[oaicite:7]{index=7}

즉, 외부 테이블은 빠르게 협업 데이터를 조회하는 데 유리하지만, 내부 테이블과는 성격이 완전히 다릅니다.


8단계. 외부 테이블에서 코멘트 데이터 조회하고 변경 사항 반영 확인

목적: 외부 연결이 실제로 동작하는지 검증하는 단계입니다.

이제 새 쿼리를 열고 아래 SQL을 실행합니다.

#standardSQL
SELECT * FROM ecommerce.products_comments WHERE comments IS NOT NULL

그러면 Google Sheets에서 입력한 comments 값이 결과에 나타납니다. 예를 들어 특정 SKU 행에 new shipment on the way가 그대로 반환됩니다. 실습 문서도 이런 결과를 표로 보여줍니다. :contentReference[oaicite:8]{index=8}

여기서 끝이 아닙니다. 다시 Google Sheets로 돌아가 코멘트를 더 수정한 뒤, BigQuery에서 같은 쿼리를 다시 실행하면 변경 사항이 반영됩니다. 이것이 외부 테이블의 가장 큰 특징입니다. 데이터 복사 없이 원본을 직접 조회하므로, 시트 수정이 곧 BigQuery 조회 결과에 영향을 줍니다. :contentReference[oaicite:9]{index=9}

이 단계가 실무적으로 중요한 이유는, 분석팀과 운영팀이 서로 다른 도구를 쓰더라도 BigQuery를 통해 연결할 수 있기 때문입니다.


실습 증거

1. CSV 업로드 후 products 테이블 생성

실습 문서는 로컬 CSV를 Upload 방식으로 적재하고, Preview 화면에서 SKU, name, orderedQuantity, stockLevel, restockingLeadTime 컬럼이 로드되었는지 확인하라고 안내합니다. 이것이 내부 테이블 생성의 핵심 증거입니다. :contentReference[oaicite:10]{index=10}

2. 동일 테이블명으로 GCS 적재 시 에러 발생

페이지 5~6 과정은 이미 존재하는 ecommerce.products 테이블 때문에 적재가 실패하고, Write Preference를 Overwrite table로 바꿔 해결하는 절차를 보여줍니다. 이는 BigQuery 쓰기 정책 이해의 핵심 증거입니다. :contentReference[oaicite:11]{index=11}

3. Google Sheets 외부 테이블 조회 결과

페이지 10 결과 표는 comments 컬럼에 new shipment on the way가 반환되는 모습을 보여줍니다. 이는 Google Sheets가 BigQuery 외부 테이블로 성공적으로 연결되었음을 보여주는 직접 증거입니다. :contentReference[oaicite:12]{index=12}


트러블슈팅

문제 증상:
GCS에서 같은 CSV를 다시 적재하려고 하자 테이블 생성이 실패한다.

원인 분석:
이미 같은 이름의 ecommerce.products 테이블이 존재하는데, BigQuery 기본 쓰기 정책이 덮어쓰기를 허용하지 않기 때문이다.

확인 방법:
Project History에서 실패한 load job 메시지를 확인한다.

해결 방법:
Repeat load job을 눌러 Create Table 폼으로 다시 들어간 뒤, Advanced Options의 Write Preference를 Overwrite table로 바꾼다.

재발 방지 방법:
같은 이름의 테이블을 다시 만들 때는 항상 쓰기 정책을 먼저 확인한다.


문제 증상:
Google Sheets 외부 테이블은 만들어졌지만, 내부 테이블처럼 빠르지 않고 조회 결과가 바뀔 수 있다.

원인 분석:
외부 테이블은 BigQuery 내부 저장이 아니라 원본 스프레드시트를 직접 참조하기 때문에 데이터 일관성과 성능에서 내부 테이블보다 불리할 수 있다.

확인 방법:
시트 내용을 변경한 뒤 같은 쿼리를 다시 실행하면 결과가 달라지는지 확인한다.

해결 방법:
협업 편의가 목적이면 외부 테이블을 유지하고, 성능과 일관성이 중요하면 BigQuery 내부 테이블로 다시 적재하는 방식을 검토한다.

재발 방지 방법:
외부 테이블은 “협업용 연결”로, 내부 테이블은 “분석용 저장”으로 구분해서 설계한다.


실무 핵심 포인트

이번 실습의 가장 중요한 교훈은 아래 한 문장으로 정리됩니다.

BigQuery는 단순 데이터 저장소가 아니라, 서로 다른 데이터 소스를 연결하는 통합 허브입니다.

즉, 로컬 CSV는 내부 테이블로 빠르게 적재하고, 반복 파일은 GCS로 관리하며, 협업 메모는 Google Sheets 외부 테이블로 연결하는 식으로 역할을 나눌 수 있습니다. 이 구조를 이해하면 이후 Looker Studio 보고서, Vertex AI 예측, 자동화 파이프라인까지 자연스럽게 확장할 수 있습니다.


결론

핵심 원칙
BigQuery 데이터 적재는 단순 업로드가 아니라, 데이터 소스 특성에 맞는 저장 방식과 연결 방식을 선택하는 작업입니다.

실무 적용 시 주의점

  • CSV 적재 후에는 Preview와 SQL로 반드시 검증할 것
  • 같은 이름의 테이블을 다시 만들 때는 Write Preference를 확인할 것
  • 외부 테이블은 협업에 유리하지만, 성능과 일관성은 내부 테이블보다 약할 수 있음
  • 분석용 데이터와 협업용 데이터를 구분해서 설계할 것

다음 학습 단계 제안
다음에는 적재한 데이터를 Looker Studio에 연결해 재고 대시보드를 만들거나, BigQuery ML로 재주문 예측 모델을 만들어보면 좋습니다.