DynamoDB 테이블을 CSV로 내보내는 법 (4가지 방법)
DynamoDB에는 네이티브 "CSV로 내보내기" 버튼이 없습니다. 모든 값은
DynamoDB의 마샬링된 JSON — {"S": "..."},
{"N": "123"}, {"M": {...}} — 으로 감싸여 돌아오고, 테이블에는 뻔한 평면 열
표현이 없는 중첩된 맵, 리스트, 세트가 담길 수 있습니다. 그래서 "DynamoDB를 CSV로
내보내기"는 사실 두 가지 문제입니다: 항목을 꺼내기, 그다음 타입이 붙은
JSON을 행으로 평탄화하기. 콘솔도 관리형 내보내기도 두 번째 단계를 대신해 주지
않습니다.
이 가이드는 두 단계를 모두 대신해 주는 방법으로 시작한 다음, 세 가지 AWS 도구 경로와 각각이 옳은 선택이 되는 경우를 다룹니다.
DynamoDB 테이블을 CSV로 어떻게 내보내나요?
가장 빠른 방법: DynoTable에서 테이블을 열고, 원하는 행으로
필터링하고, 결과를 클릭 한 번으로 CSV로 내보냅니다 — 타입 서술자는 벗겨지고 중첩
값은 대신 평탄화됩니다(방법 1). 대신
AWS 도구로 만든다면: 작은 테이블은 CLI로 스캔하고 jq로 재구성하고
(방법 2), 큰 테이블은 관리형 S3 내보내기를 쓰고
(방법 3), 맞춤 형태가 필요하면
짧은 스크립트를 씁니다(방법 4).
- 필터링 / 형태를 잡은 CSV(열 일부, 일부 항목만): GUI 내보내기(방법 1) 또는 스크립트. 관리형 S3 내보내기는 필터 없이 전체 테이블을 줍니다.
- 작은 테이블, 임시, 터미널 전용: AWS CLI
scan+jq(방법 2). 중첩 속성이 나타나기 전까지는 괜찮습니다. - 큰 테이블(GB 이상): DynamoDB의 S3로 내보내기 (방법 3), 그다음 덤프를 변환. 비동기로 실행되고 읽기 용량을 소비하지 않습니다 — 하지만 출력은 CSV가 아니라 DynamoDB JSON입니다.
방법 1: DynoTable에서 원클릭 내보내기
DynoTable은 내보내기를 탐색의 일부로 취급합니다: 쿼리를 실행하거나 필터링하고, ⌘⇧E(또는 탭 도구 모음의 Export 버튼)를 누르고, 무엇을 내보낼지 고릅니다:
- 형식: CSV(항목당 한 행, 헤더 포함 — 세트는 셀 안에 JSON 배열로
직렬화), JSON, NDJSON. JSON/NDJSON은 언마샬링된 형태(일반
"count": 3)로, 또는 큰 숫자를 보존하는 무손실 왕복이 필요할 때는 마샬링된 DynamoDB-JSON으로 나옵니다. - 범위: 현재 로드된 행, 선택만, 또는 전체 필터 매치 — 화면에 있는 것만이 아니라 쿼리에 일치하는 모든 항목을 DynamoDB에서 곧바로 스트리밍합니다. 마지막 것이 관리형 S3 스냅샷은 못 하는 필터링된 내보내기입니다.
- 대상: 클립보드 또는 파일. 일회성으로 잡아챌 때는 행을 우클릭하고 Copy as…로 CSV, JSON, NDJSON, DynamoDB-JSON을 대화 상자 없이 곧바로 클립보드에 올리세요.

아래의 DIY 경로들을 망가뜨리는 평탄화 문제들이 처리되어 있습니다: 타입 서술자는 벗겨지고, 중첩된 맵과 리스트는 평탄화되며, 이름을 바꾼 열은 CSV 헤더로 그대로 흘러갑니다. 큰 내보내기는 분리되어 백그라운드에서 실행됩니다 — 디스크에 행 단위로 스트리밍되어, 탭 전환과 심지어 앱 재로드도 이겨 냅니다 — 그래서 멀티 기가바이트 내보내기가 메모리에 다 들어갈 필요가 전혀 없습니다.
이것은 데스크톱 DynamoDB 클라이언트, 즉 테이블을 탐색할 때 이미 쓰는 그 도구입니다; 다른 DynamoDB GUI와의 비교를 보세요. 언제 쓰지 않을 까요? 내보내기가 파이프라인에서 무인으로 실행되어야 할 때 — 그게 스크립트 경로(방법 4)의 몫입니다.
방법 2: AWS CLI scan + jq
작은 테이블이라면 스캔한 뒤 jq로 출력을 재구성할 수 있습니다. Scan은 테이블의
모든 항목을 읽어 최대 1 MB 페이지로 반환합니다; CLI는 페이지네이션을
자동으로 따라가 줍니다
(AWS 문서: 테이블 스캔).
aws dynamodb scan --table-name MyTable --output json \
| jq -r '.Items[] | [.id.S, .name.S, .price.N] | @csv' \
> out.csv함정은 그 jq 줄에 있습니다: .id.S, .name.S, .price.N을 손으로 써야
합니다 — 각 속성의 타입 서술자(S, N, B, BOOL, M, L, SS, NS,
BS)를 지나쳐 원시 값에 닿기 위해서요. 문자열 열 세 개짜리 평평한 테이블이라면
감당할 만합니다. 다음이 등장하는 순간 무너집니다:
- 중첩된 맵/리스트 —
{"M": {...}}나{"L": [...]}는 평탄화해 넣을 단일 열이 없습니다;@csv가 목이 메거나, 셀을 손으로 JSON 인코딩하게 됩니다. - 세트 —
{"SS": ["a","b"]}는 스칼라가 아니라 배열입니다. - 스파스 속성 — DynamoDB는 스키마가 없으므로 항목 A에는
price가 있고 항목 B에는 없을 수 있습니다. 고정된 열 목록은 조용히 열을 누락하거나 어긋나게 만듭니다.
--output csv라는 것도 아예 없습니다 — CLI의 출력 형식은 json, yaml,
text, table, off이고, 어느 것도 DynamoDB 타입을 이해하지 못합니다. 그래서
타입 태그를 벗겨 내려면 여전히 jq(또는 스크립트)가 필요합니다. "AWS CLI로
DynamoDB 테이블을 CSV로 내보내기"가 사소한 경우를 지나면 결코 한 줄로 끝나지
않는 핵심 이유입니다.
이 방식으로 더 큰 테이블 전체를 하루 종일 걸리지 않게 내보내려면, --segment /
--total-segments로 스캔을 병렬화하고
(AWS 문서: 병렬 스캔 —
DynamoDB는 "각 항목의 파티션 키에 해시 함수를 적용해 항목을 세그먼트 에
할당"하므로 세그먼트가 고르지 않을 수 있습니다), 첫 1 MB 페이지에서 멈추지 않도록
페이지네이션을 읽으세요.
방법 3: DynamoDB의 S3로 내보내기 (큰 테이블)
크기가 좀 되는 테이블에는 관리형 Amazon S3로 내보내기가 올바른 도구입니다.
특정 시점 복구(PITR) 윈도 안의 어느 시점에서든 스냅샷을 내보내며 — 그래서
테이블에 PITR이 먼저 활성화되어 있어야 하고, 그렇지 않으면 내보내기가
PointInTimeRecoveryUnavailableException으로
실패합니다 — 비동기로 실행되고,
읽기 용량 단위를 소비하지 않아 테이블의 처리량이나 가용성에 영향이 전혀
없습니다
(AWS 문서:
"내보내기는 비동기이며, 읽기 용량 단위(RCU)를 소비하지 않고 테이블 성능과
가용성에 영향을 주지 않습니다"; "내보내기 기능을 사용하려면 테이블에 PITR을
활성화해야 합니다"). 콘솔의 Exports to S3 액션이 내부에서 트리거하는 것도
바로 이것입니다: 콘솔은 같은 API의 프런트엔드일 뿐이므로, 같은 PITR 요구 사항과
같은 JSON 출력을 그대로 지닙니다.
aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:us-east-1:123456789012:table/MyTable \
--s3-bucket my-export-bucket \
--export-format DYNAMODB_JSON한 가지 함정: S3 내보내기는 CSV를 출력하지 않습니다. DynamoDB JSON이나
Amazon Ion만을, JSON-lines 형식(한 줄에 항목
하나)의 gzip 압축 파일로, 매니페스트 파일과 함께 씁니다
(AWS 문서: 내보내기 출력 형식 —
데이터 파일은 .json.gz로 쓰이고, "형식은 JSON lines"이며,
manifest-summary.json / manifest-files.json이 함께합니다). 그 뒤에 여전히
변환 단계가 필요합니다:
- Athena / Glue는 내보낸 DynamoDB JSON을 직접 읽습니다 — S3 접두사에
테이블을 겨누고
SELECT에서 CSV를 쓰세요(이것이 흔한 "DynamoDB를 S3로, 그다음 CSV로" 파이프라인입니다). AWS는 "Athena와 AWS Glue 같은 많은 AWS 서비스가 이 형식을 자동으로 파싱합니다"라고 언급합니다 (내보내기 출력 형식). - 직접 만들기 —
.gz파일을 압축 해제하고, 각 JSON 줄을 파싱하고, 평탄화하세요(다른 모든 방법과 같은 평탄화 문제입니다).
또한 전체 테이블 스냅샷입니다: 일부 항목만 내보내는 서버 측 필터가 없습니다. 부분집합이 필요하면 Athena에서 사후에 필터링하거나, GUI(방법 1) / 스크립트를 대신 씁니다.
방법 4: 빠른 스크립트 (boto3 / Node)
내보내기가 무인으로 실행되어야 할 때 — 야간 작업, CI 단계 — 는 작은
스크립트가 위의 모든 것을 이깁니다. 이점은 AWS SDK가 타입이 붙은 JSON을 대신
언마샬링해 준다는 것입니다: boto3의 리소스 인터페이스와 JS SDK의
DynamoDBDocumentClient는 {"price": {"N": "2000"}} 대신 일반
{"price": 2000}을 반환합니다(boto3의 리소스 인터페이스는 "데이터 타입 지정을
암묵적"으로 만든다고
AWS Python 가이드
가 말하고, JS DocumentClient는 "주석이 달린 응답 데이터를 네이티브 JavaScript
타입으로 변환"한다고
@aws-sdk/lib-dynamodb
가 말합니다).
import boto3, csv
table = boto3.resource("dynamodb").Table("MyTable")
rows, resp = [], table.scan()
rows += resp["Items"]
while "LastEvaluatedKey" in resp: # paginate to the end
resp = table.scan(ExclusiveStartKey=resp["LastEvaluatedKey"])
rows += resp["Items"]
with open("out.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["id", "name", "price"])
w.writeheader()
for r in rows:
w.writerow({k: r.get(k) for k in w.fieldnames})SDK가 대신 정해 줄 수 없는 두 가지 결정은 여전히 여러분 몫입니다: 중첩된
맵/리스트를 열로 어떻게 평탄화할지(셀을 JSON 인코딩? 키를 점 경로로?), 그리고
스파스 속성을 어떻게 할지(여기서는 r.get(k)로 없는 키가 빈 셀이 됩니다).
그리고 LastEvaluatedKey 루프를 빠뜨리지 마세요 — scan() 호출 한 번은 첫
1 MB 페이지만 반환하므로, 없으면 테이블의 일부만 조용히 내보내게 됩니다.
방법 2와 같은 주의 사항: 여기의 전체 테이블 scan도 여전히 읽기 용량을 소비하고
라이브 트래픽과 경쟁합니다. 큰 테이블에는
방법 3을 선호하고 덤프를
재구성하세요.
함정: DynamoDB JSON 대 평평한 CSV
어떤 방법을 고르든, DynamoDB의 데이터 모델과 평평한 CSV 사이의 똑같은 불일치 몇 가지가 여러분을 물 것입니다:
- 타입 서술자. 원시 API / CLI / S3 내보내기 출력은 모든 값을
감쌉니다(
{"S": "..."},{"N": "123"}). SDK로 벗겨 내거나 서술자를 직접 제거해야 합니다. 전체 집합은S,N,B,BOOL,NULL,M,L,SS,NS,BS입니다 — DynamoDB 데이터 타입을 보세요. - 중첩된 맵과 리스트(
M,L)는 최대 32단계 깊이까지 중첩될 수 있고 (AWS 문서: 데이터 타입 — 리스트와 맵은 "서로 안에 중첩되어 최대 32단계 깊이의 복잡한 데이터 구조를 표현할 수 있습니다") 자연스러운 단일 열 형태가 없습니다. 미리 정하세요: 셀을 JSON 인코딩할지, 중첩 키를 점 경로 열(address.city)로 펼칠지. - 세트(
SS/NS/BS)는 스칼라가 아니라 순서 없는 컬렉션입니다 — AWS는 "세트 안 값들의 순서는 보존되지 않습니다"라고 경고합니다 (데이터 타입) — 그러니 구분자로 이어붙인 문자열로 평탄화하고 원소 순서에 의존하지 마세요. - 스파스 속성. DynamoDB는 스키마가 없으므로 두 항목이 서로 다른 속성을 가질 수 있습니다. 고정된 열 집합은 없습니다; 모든 항목에 걸쳐 키를 합집합 하지 않으면 열이 어긋납니다. 한 테이블이 여러 엔터티 형태를 담는 단일 테이블 설계의 직접적 귀결입니다.
- 페이지네이션.
Scan(과Query)은 호출당 최대 1 MB를 반환합니다.LastEvaluatedKey로 루프를 돌지 않으면 첫 페이지만 조용히 내보내게 됩니다. 페이지네이션을 보세요. - 숫자 정밀도. DynamoDB 숫자는 최대 38자리 정밀도를 지니고 문자열로 이동합니다 (AWS 문서: 데이터 타입: "숫자는 최대 38자리의 정밀도를 가질 수 있습니다"; "모든 숫자는 네트워크를 통해 DynamoDB로 문자열로 전송됩니다"); 스프레드시트 소프트웨어는 긴 숫자나 ID를 float로 강제 변환해 자릿수를 잃을 수 있습니다. 텍스트로 유지하세요.
FAQ
DynamoDB 테이블을 CSV로 내보내는 가장 빠른 방법은요? 평탄화를 대신해 주는 GUI입니다: DynoTable에서 테이블을 필터링하고, ⌘⇧E를 누르고, CSV를 고르고, 범위를 선택하세요 — 선택한 행부터 필터에 일치하는 모든 항목까지, DynamoDB에서 스트리밍됩니다. 타입 서술자와 중첩 값은 자동으로 처리됩니다.
AWS CLI로 DynamoDB 테이블을 CSV로 어떻게 내보내나요?
테이블을 스캔하고 jq로 출력을 재구성하세요(방법 2): aws dynamodb scan →
jq로 각 값의 타입 서술자 벗기기 → @csv. DynamoDB를 아는 --output csv는
없으므로 타입 벗기기는 언제나 직접 하게 되고, 중첩된 맵, 리스트, 세트에서
무너집니다.
AWS에서 DynamoDB 테이블을 곧바로 CSV로 내보낼 수 있나요?
한 단계로는 안 됩니다. 콘솔과 관리형 S3 내보내기 모두 DynamoDB JSON이나 Amazon
Ion을 만들지, 결코 CSV를 만들지 않습니다. 언제나 변환 단계가 필요합니다 — CLI +
jq, 스크립트, S3 덤프 위의 Athena/Glue, 또는 평탄화를 대신해 주는 GUI.
프로덕션에 영향 없이 DynamoDB 테이블 전체를 어떻게 내보내나요?
S3로 내보내기 기능(방법 3)을 쓰세요. 비동기로 실행되고 읽기 용량 단위를
소비하지 않으므로 라이브 트래픽과 경쟁하지 않습니다 — 테이블의 처리량에 대해
계량되는 Scan과는 다릅니다
(AWS 문서).
PITR 활성화가 필요하고, 필터링된 부분집합이 아니라 전체 테이블을 내보냅니다.
DynamoDB를 S3에 CSV로 어떻게 내보내나요?
관리형 내보내기는 S3에 DynamoDB JSON / Ion만 쓰므로, "CSV로"는 두 번째
도약입니다: 내보내기 접두사를 Athena(또는 Glue) 테이블로 등록하고 SELECT에서
CSV를 쓰세요. --export-format CSV는 없습니다.
DynamoDB를 Excel로 어떻게 내보내나요?
먼저 (위의 아무 방법으로든) CSV로 내보낸 다음, Excel에서 CSV를 여세요 — 긴 숫자
ID가 float로 강제 변환되지 않도록 텍스트로 유지하면서요. DynamoDB에서 직접
.xlsx로 내보내는 길은 없습니다; DynoTable은 현재 뷰를
스프레드시트에서 바로 쓸 수 있는 CSV로 저장합니다.
왜 내보낸 JSON 곳곳에 {"S": ...}와 {"N": ...}이 있나요?
그것이 DynamoDB의 와이어 형식입니다 — 각 값에 타입
서술자가 붙습니다. CSV를 쓰기 전에 SDK,
DynamoDB JSON 변환기, 또는 GUI로
언마샬링하세요. 와이어 형식은 데이터가 API에서 왔든, CLI에서 왔든, S3
내보내기에서 왔든 같습니다.
DynoTable로 여러분의 테이블을 탐색·필터링하고 CSV로 내보내거나, 먼저 JSON 변환기에서 DynamoDB JSON 샘플을 벗겨 보세요.


