입문8분 분량

DynamoDB 테이블을 CSV로 내보내는 방법(4가지)

DynamoDB에는 네이티브 "CSV로 내보내기" 버튼이 없습니다. 모든 값은 DynamoDB의 마샬링된 JSON{"S": "..."}, {"N": "123"}, {"M": {...}} — 으로 감싸여 돌아오고, 테이블은 평탄한 열 표현이 명확하지 않은 중첩 맵, 리스트, 집합을 담을 수 있습니다. 그래서 "DynamoDB를 CSV로 내보내기"는 사실 두 문제입니다: 항목을 꺼내기, 그다음 타입이 붙은 JSON을 행으로 평탄화하기. 콘솔도 관리형 내보내기도 두 번째 단계를 대신 해주지 않습니다.

이 가이드는 네 가지 접근을 테이블 크기와 항목이 가진 중첩의 정도에 따라 순위 매깁니다.

DynamoDB 테이블을 CSV로 내보내는 방법은?

DynamoDB에는 네이티브 CSV 내보내기 기능이 없으므로, 테이블을 스캔하거나 스냅샷을 찍은 다음 타입이 붙은 JSON을 행으로 평탄화해야 합니다. 작은 테이블에는 AWS CLI scan + jq 또는 짧은 스크립트를, 큰 테이블에는 S3로 내보낸 뒤 변환하고, 필터링된 완성형 CSV가 필요하다면 DynoTable 같은 GUI를 사용하세요.

  • 작은 테이블, 즉석: AWS CLI scan + jq, 또는 20줄짜리 스크립트 (방법 1 / 방법 3). 중첩 속성이 나타나기 전까지는 괜찮습니다.
  • 큰 테이블(GB 이상): DynamoDB S3 내보내기 (방법 2), 그다음 덤프를 변환합니다. 비동기로 실행되며 읽기 용량을 소비하지 않습니다 — 하지만 CSV가 아니라 DynamoDB JSON을 출력합니다.
  • 필터링/형태가 잡힌 CSV(열의 부분 집합, 일부 항목만): GUI 내보내기 또는 스크립트. 관리형 S3 내보내기는 필터링되지 않은 전체 테이블을 줍니다.

방법 1: 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는 없을 수 있습니다. 고정된 열 목록은 조용히 열을 누락하거나 어긋나게 합니다.

DynamoDB 타입을 이해하는 --output csv도 없습니다. CLI의 csv 출력은 원시 응답을 디스크립터까지 통째로 평탄화하므로 — 타입 태그를 벗기려면 여전히 jq(또는 스크립트)가 필요합니다. 그것이 "AWS CLI로 DynamoDB 테이블을 CSV로 내보내기"가 사소한 경우를 넘어서면 결코 한 줄짜리가 아닌 핵심 이유입니다.

이 방식으로 더 큰 테이블 전체를 하루 종일 걸리지 않게 내보내려면, --segment / --total-segments로 스캔을 병렬화하세요 (AWS 문서: 병렬 스캔 — DynamoDB는 "각 항목의 파티션 키에 해시 함수를 적용해 항목을 세그먼트에 할당"하므로 세그먼트가 고르지 않을 수 있음). 그리고 첫 1 MB 페이지에서 멈추지 않도록 페이지네이션을 읽으세요.

방법 2: DynamoDB S3 내보내기(큰 테이블)

실제로 규모 있는 테이블에는 관리형 Amazon S3로 내보내기가 적합한 도구입니다. 특정 시점 복구(PITR) 윈도 안의 어느 시점에서 스냅샷을 내보내므로 — 따라서 테이블에 먼저 PITR이 활성화되어 있어야 합니다 — 비동기로 실행되고, 읽기 용량 단위를 소비하지 않아 테이블 처리량 이나 가용성에 영향이 전혀 없습니다 (AWS 문서: "내보내기는 비동기이며 읽기 용량 단위(RCU)를 소비하지 않고 테이블 성능과 가용성에 영향이 없습니다"; "내보내기 기능을 사용하려면 테이블에 PITR을 활성화해야 합니다"). 이는 콘솔의 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만, gzip된 JSON 라인 형식(줄당 항목 하나)의 파일로, 매니페스트 파일과 함께 씁니다(AWS 문서: 내보내기 출력 형식 — 데이터 파일은 .json.gz로 작성되고, "형식은 JSON 라인"이며, 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를 대신 사용합니다.

방법 3: 빠른 스크립트(boto3 / Node)

형태가 잡힌 CSV — 특정 열, 필터링된 부분 집합, 중첩 필드에 대한 맞춤 처리 — 가 필요할 때, 작은 스크립트가 jq와 씨름하는 것을 이깁니다. 이점은 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:                  # 끝까지 페이지 넘기기
    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 페이지만 반환하므로, 없으면 테이블의 일부만 조용히 내보냅니다.

방법 1과 같은 주의: 여기서도 전체 테이블 scan은 읽기 용량을 소비하고 라이브 트래픽과 경합합니다. 큰 테이블에는 방법 2를 선호하고 덤프를 재구성하세요.

방법 4: DynoTable의 원클릭 내보내기

스크립트와 CLI 경로는 동작하지만, 매번 같은 평탄화와 페이지네이션 로직을 다시 만듭니다. DynoTable은 대신 해줍니다: 쿼리를 실행하거나 필터링한 다음, 보이는 행을 곧장 CSV(또는 Excel)로 내보냅니다 — 타입 디스크립터가 풀리고, 중첩 맵과 리스트가 평탄화되고, 집합이 처리되며, 출력에는 여러분이 실제로 원하는 항목과 열만 담깁니다.

현재 뷰를 내보내므로, 방법 2의 전체 테이블 스냅샷이 줄 수 없는 필터링/형태가 잡힌 CSV를 — 스캔 루프를 작성하지 않고 — 얻습니다. 테이블을 둘러볼 때 이미 사용하는 바로 그 데스크톱 DynamoDB 클라이언트입니다. 다른 DynamoDB GUI와 어떻게 견주는지 보세요.

함정: 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를 부동소수점으로 강제 변환해 자릿수를 잃을 수 있습니다. 텍스트로 유지하세요.

FAQ

AWS CLI로 DynamoDB 테이블을 CSV로 내보내려면 어떻게 하나요? 테이블을 스캔해서 출력을 jq로 재구성하세요(방법 1): aws dynamodb scan → 각 값의 타입 디스크립터를 벗기는 jq@csv. DynamoDB를 인식하는 --output csv가 없으므로 타입 벗기기는 항상 직접 하게 되며, 중첩 맵, 리스트, 집합에서 깨집니다.

AWS에서 DynamoDB 테이블을 곧장 CSV로 내보낼 수 있나요? 한 단계로는 안 됩니다. 콘솔과 관리형 S3 내보내기 모두 CSV가 아니라 DynamoDB JSON 또는 Amazon Ion을 생성합니다. 항상 변환 단계가 필요합니다 — CLI + jq, 스크립트, S3 덤프에 대한 Athena/Glue, 또는 평탄화를 대신 해주는 GUI.

프로덕션에 영향을 주지 않고 DynamoDB 테이블 전체를 내보내려면 어떻게 하나요? S3로 내보내기 기능을 사용하세요(방법 2). 비동기로 실행되고 읽기 용량 단위를 소비하지 않아 라이브 트래픽과 경합하지 않습니다 — 테이블 처리량에 과금되는 Scan과 달리요 (AWS 문서). PITR 활성화가 필요하고, 필터링된 부분 집합이 아니라 전체 테이블을 내보냅니다.

DynamoDB를 S3로 CSV로 내보내려면 어떻게 하나요? 관리형 내보내기는 S3에 DynamoDB JSON / Ion만 쓰므로, "CSV로"는 두 번째 단계입니다: 내보내기 접두사를 Athena(또는 Glue) 테이블로 등록한 다음 SELECT에서 CSV를 쓰세요. --export-format CSV는 없습니다.

DynamoDB를 Excel로 내보내려면 어떻게 하나요? 먼저 CSV로 내보낸 다음(위 어떤 방법이든), Excel에서 CSV를 여세요 — 긴 숫자 ID가 부동소수점으로 강제 변환되지 않도록 텍스트로 유지하면서요. DynamoDB에서 직접 .xlsx로 내보내는 것은 없습니다. DynoTable 같은 GUI가 현재 뷰를 곧장 스프레드시트용 CSV로 저장할 수 있습니다.

내보낸 JSON에 왜 {"S": ...}{"N": ...}이 사방에 있나요? 그것이 DynamoDB의 마샬링된 와이어 형식입니다 — 각 값에 타입 디스크립터가 태그됩니다. CSV를 쓰기 전에 SDK, DynamoDB JSON 변환기, 또는 GUI로 언마샬링하세요. 와이어 형식은 데이터가 API, CLI, S3 내보내기 중 어디서 왔든 같습니다.

DynoTable로 여러분의 테이블을 둘러보고, 필터링하고, CSV로 내보내거나, 먼저 JSON 변환기에서 DynamoDB JSON 샘플을 풀어보세요.

업데이트됨