SQL Server 대용량 데이터 import/export 도구 - bcp

https://learn.microsoft.com/ko-kr/sql/tools/bcp-utility?view=sql-server-ver16&tabs=windows
1. bcp란 무엇인가?
bcp(Bulk Copy Program)는 Microsoft SQL Server에서 제공하는 대용량 데이터 Import/Export 도구입니다.
SSMS(SQL Server Management Studio)에서 결과 저장 기능을 쓰면 수십만 건 이상에서 속도가 느려지지만,
bcp를 이용하면 수백만 건의 데이터를 빠르고 안정적으로 파일로 추출할 수 있습니다.
👉 즉,
- 테이블 전체를 내보내기 (export)
- 쿼리 결과를 파일로 저장하기
- CSV, TXT, Native 포맷 등 다양한 형식 지원
- 수백만 건도 빠르게 처리
이게 bcp의 장점입니다.
2. bcp 기본 구조
테이블 → 파일 (Export)
- out : 테이블 데이터를 파일로 내보내기
- -c : 문자 형식 (char)
- -t, : 구분자(쉼표 → CSV)
- -S : 서버명 (예: localhost, 192.168.0.10\SQLEXPRESS)
- -U/-P : SQL 로그인 계정/비밀번호
쿼리 → 파일 (Export)
bcp "SELECT Col1, Col2 FROM MyTable WHERE CreateDate >= '2025-01-01'" queryout "D:\data.csv" -c -t, -S localhost -d MyDB -U sa -P MyPassword
- queryout : SELECT 결과를 파일로 내보내기
- -d MyDB : 데이터베이스 지정 (쿼리에 DB명 안 썼을 때 필요)
파일 → 테이블 (Import)
bcp MyDB.dbo.MyTable in "D:\data.csv" -c -t, -S localhost -U sa -P MyPassword
- in : 파일 데이터를 테이블로 적재
3. 실습 예제
3-1. 간단한 Export
예를 들어, Sales 테이블을 CSV로 추출한다고 하면:
bcp MyDB.dbo.Sales out "D:\sales.csv" -c -t, -S localhost -U sa -P MyPassword
👉 D:\sales.csv 파일이 생성되고, 쉼표로 구분된 텍스트 파일이 나옵니다.
3-2. 조건 있는 Export
2025년 이후 데이터만 추출하고 싶다면:
bcp "SELECT * FROM Sales WHERE OrderDate >= '2025-01-01'" queryout "D:\sales_2025.csv" -c -t, -S localhost -d MyDB -U sa -P MyPassword
3-3. 대용량 데이터 분할 Export
Excel은 1,048,576 행까지만 표시할 수 있습니다.
따라서 700만 건 데이터를 뽑을 때는 100만 행 단위로 쪼개기가 필요합니다.

SQL에서 ROW_NUMBER()로 행 번호를 붙이고, 범위별로 export:
bcp "SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn, * FROM Sales ) t WHERE rn BETWEEN 1 AND 1000000" queryout "D:\sales_part1.csv" -c -t, -S localhost -d MyDB -U sa -P MyPassword bcp "SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn, * FROM Sales ) t WHERE rn BETWEEN 1000001 AND 2000000" queryout "D:\sales_part2.csv" -c -t, -S localhost -d MyDB -U sa -P MyPassword
👉 이렇게 하면 sales_part1.csv ~ sales_part7.csv까지 나눠서 700만 건을 안전하게 추출할 수 있습니다.
5. 마무리
bcp는 단순한 명령어지만, 대용량 데이터 추출/적재에는 SSMS나 Excel보다 훨씬 강력합니다.
특히 수백만 건 이상 데이터를 다룰 때는 bcp를 익혀두면 운영/분석/백업 자동화까지 모두 활용 가능합니다.
👉 요약
- out = 테이블 전체 export
- queryout = 쿼리 결과 export
- in = 파일 import
- Excel은 100만 행 제한이 있으니, 필요하면 쪼개서 export
6. 스크립트 (bat 파일 생성 후 실행)
@echo off
setlocal enabledelayedexpansion
REM --- 환경 변수 설정 ---
set "SERVER=111.111.111.111"
set "DB=9021"
set "USER=SF"
set "PWD=test"
set "TABLE=[dbo].[DataArchive_2015_2017]"
set "OUTPUT_DIR=C:\export"
set "ROWS_PER_FILE=1000000"
set "TOTAL_ROWS=7074269"
REM --- 컬럼명 ---
set "HEADER=------실제 테이블 전체 컬럼 이 컬럼들은 excel 의 헤더로 박음----------"
REM --- 파일 개수 계산 ---
set /a FILE_COUNT=!TOTAL_ROWS! / !ROWS_PER_FILE!
set /a REMAIN=!TOTAL_ROWS! %% !ROWS_PER_FILE!
if !REMAIN! NEQ 0 set /a FILE_COUNT+=1
REM --- 폴더 생성 ---
if not exist "!OUTPUT_DIR!" mkdir "!OUTPUT_DIR!"
echo Starting export of !TOTAL_ROWS! rows into !FILE_COUNT! files...
REM --- 각 파일별로 처리 ---
set CURRENT_FILE=1
:LOOP
if !CURRENT_FILE! GTR !FILE_COUNT! goto :END
REM --- 행 범위 계산 ---
set /a START_ROW=(!CURRENT_FILE! - 1) * !ROWS_PER_FILE! + 1
set /a END_ROW=!CURRENT_FILE! * !ROWS_PER_FILE!
if !END_ROW! GTR !TOTAL_ROWS! set END_ROW=!TOTAL_ROWS!
echo.
echo ### Processing file !CURRENT_FILE! of !FILE_COUNT! (rows !START_ROW! to !END_ROW!) ###
REM --- 파일명 설정 ---
set "FINAL_FILE=!OUTPUT_DIR!\export_part_!CURRENT_FILE!.csv"
set "TEMP_FILE=temp_data_!CURRENT_FILE!.csv"
set "TEMP_SQL=temp_query_!CURRENT_FILE!.sql"
REM --- 헤더 작성 ---
echo !HEADER! > "!FINAL_FILE!"
REM --- SQL 쿼리 파일 생성 ---
echo SET NOCOUNT ON > "!TEMP_SQL!"
echo SELECT !HEADER! >> "!TEMP_SQL!"
echo FROM ( >> "!TEMP_SQL!"
echo SELECT !HEADER!, ROW_NUMBER() OVER (ORDER BY "실제테이블컬럼 저는 DATE컬럼기준 정렬" ASC) AS rn >> "!TEMP_SQL!"
echo FROM !TABLE! >> "!TEMP_SQL!"
echo ) AS ranked_data >> "!TEMP_SQL!"
echo WHERE rn BETWEEN !START_ROW! AND !END_ROW! >> "!TEMP_SQL!"
REM --- SQLCMD 실행 ---
echo Running SQLCMD...
sqlcmd -S!SERVER! -d!DB! -U!USER! -P!PWD! -i"!TEMP_SQL!" -o"!TEMP_FILE!" -h-1 -s"," -W
REM --- 결과 처리 (아무 필터링 없이 그대로 복사) ---
if exist "!TEMP_FILE!" (
echo Temp file created - copying all content...
type "!TEMP_FILE!" >> "!FINAL_FILE!"
echo Renaming temp file for inspection...
copy "!TEMP_FILE!" "debug_temp_!CURRENT_FILE!.csv"
del "!TEMP_FILE!"
echo File !CURRENT_FILE! completed - final size:
dir "!FINAL_FILE!" | findstr "export_part"
echo Temp file backup: debug_temp_!CURRENT_FILE!.csv
echo.
) else (
echo ERROR: Temp file was not created
)
REM --- 정리 ---
if exist "!TEMP_SQL!" del "!TEMP_SQL!"
REM --- 다음 파일로 ---
set /a CURRENT_FILE+=1
goto :LOOP
:END
echo.
echo ### All files exported! ###
echo Check files in: !OUTPUT_DIR!
echo Debug temp files saved for inspection
pause


꼭 DB 서버에서 bcp 실행할 필요는 없음. 그냥 client 에서도 DB 연결 가능하면 bcp 가능