본문으로 건너뛰기
snowflake검색
수집과 연동

COPY INTO 와 스테이지 (대량 적재, 파일 포맷, 언로드)

내부와 외부 스테이지, 스토리지 통합, 파일 포맷, COPY INTO 의 오류 처리와 중복 방지 기록, 변환 적재, 파일 크기 권장, 테이블에서 파일로 내보내는 언로드까지 대량 적재의 기본을 정리합니다.

COPY INTO스테이지스토리지 통합파일 포맷ON_ERROR언로드2026-10 기준, 약 8분상태 표시 설명

스테이지 종류

스테이지위치표기쓰임
사용자 스테이지Snowflake 내부, 사용자마다@~개인 파일
테이블 스테이지Snowflake 내부, 테이블마다@%orders한 테이블에만 넣을 파일
이름 있는 내부 스테이지Snowflake 내부@raw.int_stage팀이 공유하는 업로드 장소
외부 스테이지S3, GCS, Azure Blob@raw.s3_stage데이터 레이크 파일 적재

내부 스테이지는 PUT 명령(SnowSQL, Snowflake CLI, 드라이버)으로 파일을 올리고, 외부 스테이지는 클라우드 버킷을 가리킵니다. 2026년 3월에는 내부 스테이지에 대한 공개 접근을 막으면서 IP 허용 목록 예외를 두는 기능이 GA 가 되었습니다.

스토리지 통합으로 외부 스테이지 만들기

비밀 키를 스테이지에 직접 넣지 말고 스토리지 통합(Storage Integration) 으로 클라우드 IAM 역할을 신뢰하게 만듭니다.

CREATE STORAGE INTEGRATION s3_int
  TYPE = EXTERNAL_STAGE
  STORAGE_PROVIDER = 'S3'
  ENABLED = TRUE
  STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::123456789012:role/snowflake-load'
  STORAGE_ALLOWED_LOCATIONS = ('s3://my-lake/raw/');

DESC INTEGRATION s3_int;   -- STORAGE_AWS_IAM_USER_ARN, STORAGE_AWS_EXTERNAL_ID 를 AWS 신뢰 정책에

CREATE STAGE raw.s3_stage
  URL = 's3://my-lake/raw/'
  STORAGE_INTEGRATION = s3_int
  FILE_FORMAT = raw.csv_fmt;

파일 포맷

CREATE FILE FORMAT raw.csv_fmt
  TYPE = CSV
  FIELD_DELIMITER = ','
  PARSE_HEADER = TRUE                   -- 헤더로 열 이름 매칭 (MATCH_BY_COLUMN_NAME 과 함께)
  FIELD_OPTIONALLY_ENCLOSED_BY = '"'
  NULL_IF = ('', 'NULL')
  EMPTY_FIELD_AS_NULL = TRUE
  ENCODING = 'UTF8';

CREATE FILE FORMAT raw.parquet_fmt TYPE = PARQUET;
CREATE FILE FORMAT raw.json_fmt TYPE = JSON STRIP_OUTER_ARRAY = TRUE;

COPY INTO 기본

COPY INTO raw.orders
FROM @raw.s3_stage/orders/2026/10/
FILE_FORMAT = (FORMAT_NAME = 'raw.csv_fmt')
MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE
ON_ERROR = 'ABORT_STATEMENT'
PATTERN = '.*[.]csv[.]gz';

-- 실제로 넣지 않고 검사만
COPY INTO raw.orders FROM @raw.s3_stage/orders/ VALIDATION_MODE = 'RETURN_ERRORS';

ON_ERROR 선택

값동작맞는 경우
ABORT_STATEMENT (COPY 기본)오류 하나면 전체 취소정합성이 중요한 원장
CONTINUE오류 행만 건너뜀로그, 이벤트
SKIP_FILE오류가 있는 파일 통째로 건너뜀 (Snowpipe 기본)파일 단위 재처리
SKIP_FILE_n, SKIP_FILE_n%오류가 n 개 또는 n% 넘으면 파일 건너뜀약간의 오류는 허용

건너뛴 행은 VALIDATE(raw.orders, JOB_ID => '_last') 로 다시 볼 수 있습니다.

중복 적재 방지 (로드 메타데이터)

COPY 는 테이블마다 64일 동안 어떤 파일을 넣었는지 기억해 같은 파일을 다시 넣지 않습니다. 파일 이름과 ETag(체크섬)이 기준입니다.

  • 같은 이름으로 내용을 바꿔 다시 올리면 ETag 가 달라져 다시 적재됩니다.
  • 64일이 지나 기록이 없어진 파일은 상태를 알 수 없어 기본적으로 건너뜁니다. LOAD_UNCERTAIN_FILES = TRUE 로 넣거나 FORCE = TRUE 로 무조건 다시 넣을 수 있습니다.
SELECT file_name, status, row_count, row_parsed, first_error_message, last_load_time
FROM snowflake.account_usage.copy_history
WHERE table_name = 'ORDERS' AND last_load_time > DATEADD(day, -1, CURRENT_TIMESTAMP())
ORDER BY last_load_time DESC;

변환하면서 적재

COPY INTO raw.orders (id, ordered_at, amount, src_file)
FROM (
  SELECT $1::NUMBER, TO_TIMESTAMP_NTZ($2), $3::NUMBER(12,2), METADATA$FILENAME
  FROM @raw.s3_stage/orders/
)
FILE_FORMAT = (FORMAT_NAME = 'raw.csv_fmt');

열 순서 바꾸기, 형 변환, 일부 열만, 파일 이름 같은 메타데이터 열 추가 정도는 COPY 안에서 합니다. 조인이나 집계 같은 무거운 변환은 적재 후 Dynamic Tables 에서 합니다.

파일 크기와 웨어하우스

  • 권장 파일 크기는 압축 후 100~250 MB 입니다. 수 KB 파일 수십만 개는 파일마다 드는 오버헤드 때문에 느리고, 수십 GB 파일 하나는 병렬로 나뉘지 않습니다.
  • COPY 는 파일 단위로 병렬 처리됩니다. 웨어하우스를 키우면 동시에 처리하는 파일 수가 늘어나므로 파일이 충분히 많을 때만 큰 웨어하우스가 효과가 있습니다.
  • 한 번에 넣을 파일이 많지 않다면 XS 나 S 로 충분하고, 수시로 들어오는 파일은 Snowpipe 가 더 쌉니다.

언로드 (테이블에서 파일로)

COPY INTO @raw.s3_stage/export/orders_
FROM (SELECT * FROM mart.orders WHERE d = '2026-10-20')
FILE_FORMAT = (TYPE = PARQUET)
HEADER = TRUE
MAX_FILE_SIZE = 268435456     -- 약 256 MB
OVERWRITE = TRUE;

PARTITION BY 로 경로를 나눠 쓸 수 있습니다. 외부 시스템이 Snowflake 데이터를 계속 읽어야 한다면 파일 언로드보다 Iceberg 테이블 이나 데이터 공유 가 낫습니다.

트러블슈팅

  • 증상: COPY 가 성공했다고 하는데 0 행이 들어갑니다.

  • 원인: 이미 64일 안에 넣은 파일이라 건너뛰었거나, PATTERN 이 파일 경로와 맞지 않습니다.

  • 해결: 결과의 status 가 LOAD_SKIPPED 인지 보고, LIST @stage/path 로 실제 경로와 패턴을 맞춥니다. 일부러 다시 넣을 때만 FORCE = TRUE 를 씁니다.

  • 증상: "Access Denied" 또는 "is not authorized to perform sts:AssumeRole" 가 납니다.

  • 원인: AWS IAM 역할의 신뢰 정책에 Snowflake IAM 사용자 ARN 이나 외부 ID 가 빠졌거나 STORAGE_ALLOWED_LOCATIONS 밖의 경로입니다.

  • 해결: DESC INTEGRATION 값을 그대로 신뢰 정책에 넣고 경로를 확인합니다. 더 많은 오류는 적재 오류 트러블슈팅 에 있습니다.

공식 문서

이 문서에서