Quick Reference
COPY staging_users (email, name, created_at)
FROM '/var/lib/postgresql/import/users.csv'
WITH (FORMAT csv, HEADER true);\copy staging_users (email, name, created_at)
FROM './users.csv'
WITH (FORMAT csv, HEADER true)DB server가 파일을 읽게 할 수 있고 pg_read_server_files 같은 server-file 권한을 관리할 수 있을 때만 SQL COPY를 씁니다. 작업자의 로컬 파일은 psql meta-command인 \copy로 올립니다. COPY FROM은 대상 table의 INSERT 권한도 필요하고 RLS table에서는 지원되지 않으므로, 원본 신뢰도·중복 처리·실패 복구가 불명확하면 staging table부터 적재합니다.
문법
COPY는 서버 파일, \copy는 클라이언트 파일을 읽는다
COPY ... FROM '/path/file.csv'는 PostgreSQL 서버 프로세스가 접근할 수 있는 파일을 읽습니다. 그래서 파일 경로, 권한, 컨테이너 volume 위치가 서버 기준이어야 합니다. 반면 psql의 \copy는 클라이언트 쪽 파일을 읽어서 서버로 전송합니다.
-- 서버 파일 기준
COPY products
FROM '/var/lib/postgresql/import/products.csv'
WITH (FORMAT csv, HEADER true);-- psql 클라이언트가 보는 로컬 파일 기준
\copy products FROM './products.csv' WITH (FORMAT csv, HEADER true)운영 배치나 컨테이너 환경에서는 이 차이가 중요합니다. 파일이 애플리케이션 서버에는 있어도 DB 서버에는 없으면 SQL COPY는 실패합니다.
staging table을 거치면 검증과 변환을 분리할 수 있다
대량 데이터를 바로 운영 테이블에 넣기보다 staging table에 먼저 적재하면 타입 변환, 중복 검사, 외래 키 검증, 누락값 보정 과정을 분리할 수 있습니다.
CREATE TEMP TABLE staging_users (
email TEXT,
name TEXT,
created_at TEXT
);
COPY staging_users
FROM '/tmp/users.csv'
WITH (FORMAT csv, HEADER true);
INSERT INTO users (email, name, created_at)
SELECT email, name, created_at::timestamptz
FROM staging_users
WHERE email IS NOT NULL;CSV의 날짜 형식이나 빈 문자열 정책이 애플리케이션 스키마와 다르면, staging 단계에서 명시적으로 변환하는 편이 오류 위치를 추적하기 쉽습니다.
COPY FROM이 중간에 실패하면 이미 넣은 행은 현재 transaction에서는 보이지 않더라도 디스크 공간을 차지할 수 있습니다. 큰 적재는 transaction 경계와 rollback 전략을 정하고, 실패 뒤에는 VACUUM 필요 여부와 staging table 정리까지 확인합니다.
운영 기준
| 상황 | 접근 |
|---|---|
| 서버 안의 파일을 DB가 직접 읽음 | COPY |
| 로컬 파일을 psql에서 올림 | \copy |
| 원본 데이터 품질이 불확실함 | staging table 후 검증 |
| 대량 적재 후 실행 계획이 흔들림 | ANALYZE 실행 |
| 중복 키가 섞일 수 있음 | staging 후 ON CONFLICT 처리 |
대량 적재 직후에는 테이블 통계가 실제 분포와 달라질 수 있습니다. 이후 조회 성능이 중요하면 ANALYZE target_table;로 통계를 갱신합니다.
주의할 점
COPY FROM은 많은 행을 빠르게 넣기 때문에 실패했을 때 영향 범위도 큽니다. 운영 테이블에 바로 넣기 전 staging table에서 행 수, NULL, 중복, 타입 변환 오류를 확인하세요.
CSV 옵션은 원본 형식과 정확히 맞아야 합니다. HEADER, delimiter, quote, escape 설정이 다르면 열이 밀리거나 문자열이 잘못 해석될 수 있습니다.
참고 링크
1 sources