Amazon DynamoDB の bulk put items で S3 のデータを既存テーブルへ登録してみた

Amazon DynamoDB の bulk put items で S3 のデータを既存テーブルへ登録してみた

Amazon DynamoDB の bulk put items で、S3 の 10 KB のアイテムを100件から10万件まで東京リージョンの既存テーブルへ登録しました。全件が入り、所要時間は BatchWriteItem より長くなりました。入力を分けると短く、書き込み料金は試算で安くなりました。
2026.11.15

はじめに

2026年11月5日、Amazon DynamoDB の bulk put items が一般提供されました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/11/amazon-dynamodb-now-supports-bulk-put-items/

bulk put items は、S3 に置いたデータを既存の DynamoDB テーブルへ書き込む非同期ジョブです。

この記事では、東京リージョンの Standard の performance tier で、10 KB のアイテムを100件(約 1 MB)から10万件(約 1 GB)まで登録しました。登録件数と内容を確認したほか、同じデータを別のテーブルへ BatchWriteItem と PutItem で書き込んで、所要時間を比べました。入力ファイルを分けた場合の所要時間と、書き込み料金も調べました。

準備

入力ファイル

公式ブログによると、入力には行区切りの DynamoDB JSON または Ion を使用でき、gzip / zstd で圧縮することもできます。

https://aws.amazon.com/blogs/database/introducing-bulk-put-items-for-amazon-dynamodb-load-data-from-amazon-s3-into-existing-tables-at-scale/

100件の入力は、DynamoDB JSON で1行に1アイテムを書いたファイル1つです。ファイルは100行、1,027,500 バイトで、1アイテムは属性名と値の合計で 10,240 バイトです。1行の形は次のとおりです。payload は 10,000 文字ほどのランダムな文字列で、ここでは ... に置き換えています。

{"Item":{"id":{"S":"item-0001-a6119290"},"payload":{"S":"..."}}}

件数を増やした条件でも、1アイテムの大きさ(10,240 バイト)と形は同じです。入力全体の大きさは、1,000件が 10,275,000 バイト、5,000件が 51,375,000 バイト、10万件が 1,027,500,000 バイト(10ファイルの合計)でした。

実行と結果の確認

起動

100件の入力で、次のコマンドを実行しました。

aws dynamodb start-bulk-put-items \
  --table-name <テーブル名> \
  --input-s3-configuration "S3Bucket=<入力バケット>,S3KeyPrefix=input/,InputFormat=DYNAMODB_JSON" \
  --output-s3-configuration "S3Bucket=<入力バケット>,S3KeyPrefix=report/run1/,OutputType=ERROR,CONDITION_CHECK_FAILURE" \
  --performance-tier STANDARD

同じ入力で4回実行しました。1回目は、呼び出しから約 0.75 秒で応答が返りました。応答には、状態 IN_PROGRESS と bulk operation の ARN が含まれていました。

完了までの状態

返された ARN を使い、describe-bulk-operation で状態を確認しました。

aws dynamodb describe-bulk-operation --bulk-operation-arn <ARN>

1回目の完了時の応答から、結果に関わるフィールドを抜粋します。

{
    "BulkOperationDescription": {
        "BulkOperationStatus": "COMPLETED",
        "StartTime": "2026-11-06T11:42:01.523000+09:00",
        "EndTime": "2026-11-06T11:43:16.941000+09:00",
        "ProcessedItemCount": 100,
        "ProcessedInputBytes": 1027500,
        "TotalInputBytes": 1027500,
        "FailedItemCount": 0,
        "PerformanceTier": "STANDARD"
    }
}

4回とも COMPLETED になり、処理件数は100、失敗件数は0でした。

実行中の件数の推移を記録したのは4回目だけです。約5秒間隔のポーリングのうち、IN_PROGRESS の最初と最後の記録、および COMPLETED の記録を示します。その間の記録もすべて IN_PROGRESS、processed 0、failed 0 でした。

POLL 2026-11-06T11:50:10.506+0900 status/processed/failed/processedBytes/totalBytes/endTime: IN_PROGRESS	0	0	None	None	None
POLL 2026-11-06T11:51:16.294+0900 status/processed/failed/processedBytes/totalBytes/endTime: IN_PROGRESS	0	0	None	None	None
POLL 2026-11-06T11:51:21.726+0900 status/processed/failed/processedBytes/totalBytes/endTime: COMPLETED	100	0	1027500	1027500	2026-11-06T11:51:16.767000+09:00

4回目の記録では、COMPLETED になるまで処理件数が0のままで、途中の値から進み具合を読むことはできませんでした。公式ブログには、実行の初めの数分は準備のためにカウンタが動かず、この準備時間は固定の起動時間だと書かれています。

レポート

出力先には manifest-files.json が1つだけ作成され、中身は入力ファイルの処理状況を示す1行でした。

report/run1/AWSDynamoDB/BulkOperation/<ACCOUNT_ID>:<操作ID>/manifest-files.json   196 バイト
{"inputSourceArn":"arn:aws:s3:::<入力バケット>/input/items.jsonl","fileProcessingStatus":"FULLY_PROCESSED","processedRanges":[[0,99]],"etag":"<ETag>"}

出力種別には ERROR と CONDITION_CHECK_FAILURE を指定しましたが、これらに対応するオブジェクトは出力されませんでした。今回は FailedItemCount が 0 で、入力に条件式も付けていませんでした。2回目以降の出力も同じでした。

登録内容

1回目が COMPLETED になった後、強い整合性の Scan で、実行前は空だったテーブルの内容を入力と照合しました。次は、件数、キーの集合、アイテムサイズ、payload の SHA-256 を比べた結果です。

{
  "checked_at": "2026-11-06T02:43:35+00:00",
  "table": "bulkput-verify-bulk",
  "expected_count": 100,
  "scan_count": 100,
  "missing_keys": [],
  "extra_keys": [],
  "item_sizes_in_table": [
    10240
  ],
  "size_mismatch": [],
  "hash_mismatch": [],
  "ok": true
}

2〜4回目も、実行前は空だったテーブルで同じ照合を行い、すべて一致しました。

所要時間の比較

計測条件

同じデータを別のテーブルへ BatchWriteItem(25件ずつ、逐次)と PutItem(1件ずつ、逐次)で書き込み、bulk put items と所要時間を比べました。

計測した区間は、方式ごとに次のとおり異なります。

  • bulk put items:start-bulk-put-items を呼ぶ直前から、COMPLETED を返した describe-bulk-operation のポーリングまでを測りました。S3 へのアップロードは、計測の前に済ませています。ポーリングは約5秒間隔のため、完了から記録までに最大約5秒の遅れがあります。
  • BatchWriteItem と PutItem:最初の書き込みの直前から、最後の書き込みの完了までを測りました。UnprocessedItems が返った場合は、再投入して全件が入るまでを測っています。入力は、計測の前に手元のファイルから読み込んでおきました。

実行環境は次のとおりです。

  • 接続:手元の Linux 環境から、東京リージョンへインターネット経由
  • bulk put items:AWS CLI(2.39.5 と 2.40.3)
  • BatchWriteItem と PutItem:boto3(リトライは standard モード、max_attempts は 10)
  • テーブル:bulk put items 用と比較用のどちらもオンデマンド、キーは id のみ、GSI なし

テーブルの使い方は、条件ごとに次のとおり異なります。

  • 1,000件、5,000件:bulk put items 用と比較用のテーブルを1つずつ作り、2条件で共用しました。各回の前に全件削除しています。
  • 10万件:方式ごとに新しいテーブルを作り、測定後にテーブルごと削除しました。削除にも書き込み料金がかかるため、各回の前の全件削除はしていません。

件数を増やした結果

各方式1回の測定です。5,000件を10ファイルに分けた結果は、次の節に示します。

件数(入力サイズ) bulk put items(秒) bulk put items の入力ファイル数 BatchWriteItem(秒) PutItem(秒)
1,000(約 10 MB) 117.3 1 1.917 18.181
5,000(約 51 MB) 430.6 1 12.573 85.137
10万(約 1 GB) 1,523.3 10 252.4 未測定

10万件の PutItem は、費用と所要時間を理由に測っていません。bulk put items の所要時間は、どの件数でも BatchWriteItem より長くなりました。BatchWriteItem に対する倍率は、1,000件(1ファイル)で約61倍、5,000件(1ファイル)で約34倍、10万件(10ファイル)で約6.0倍でした。

どの条件でも、テーブルには全件が欠落なく入りました。強い整合性の Scan で、件数、キーの集合、アイテムサイズ、payload の SHA-256 を入力と照合し、すべて一致しました。bulk put items はすべて COMPLETED になり、失敗件数は0、レポートにもエラーはありませんでした。

BatchWriteItem は、件数が増えると UnprocessedItems が返りました。計測用のスクリプトが再投入し、最終的に全件が入っています。

件数 UnprocessedItems の延べ件数 API の呼び出し回数(最小回数) SDK のリトライ
1,000 45 47(40) 0回
5,000 394 277(200) 0回
10万 5,845 5,201(4,000) 5回

スロットル例外は、どの条件でも発生しませんでした。

10万件では、書き込みが行われた 20:47〜20:52(日本時間)の WriteThrottleEvents が、1分ごとの値の合計で約5,800回でした。UnprocessedItems の延べ件数とほぼ同じです。この書き込みは 100万 WRU を約252秒で消費しており、平均で1秒あたり約3,960 WRU でした。

入力ファイルの分割

公式ブログは、サービスが入力オブジェクト単位で並列に処理するため、大きなデータは同じ大きさの複数のオブジェクトに分けるよう案内しています。そこで、5,000件の入力を500件ずつ10ファイルに分け、同じ S3 プレフィックスに置いて bulk put items を1回実行しました。入力の中身は1ファイル版と同じですが、実行した日時とテーブルは別です。

split -l 500 -d -a 2 --additional-suffix=.jsonl items-5000.jsonl part-
入力 bulk put items の所要時間(秒)
1ファイル 430.6
10ファイル 144.8

所要時間は約3分の1になりました。それでも BatchWriteItem(12.6秒)の約11.5倍かかっています。

書き込み料金の比較

東京リージョンの単価は、2026年11月15日に取得した AWS Price List(2026年11月11日公開版)の値です。

項目 単価
bulk put items(performance tier が Standard、テーブルクラスが Standard) $0.1144 / GB
オンデマンドの書き込み(テーブルクラスが Standard) $0.715 / 100万 WRU

10 KB のアイテム10万件(約 1 GB)の場合の計算です。

  • bulk put items:describe-bulk-operation の応答の BulkOperationUsage にある BulkPutBytes は、1,024,000,000 バイトでした。1 GB を 10^9 バイトとして、約 $0.117 です
  • BatchWriteItem:1 WRU は 1 KB の書き込みなので、10 KB のアイテムは 10 WRU です。10万件で 1,000,000 WRU となり、CloudWatch の ConsumedWriteCapacityUnits の合計も同じ値でした。単価を掛けると $0.715 です

10 KB のアイテム、GSI のないオンデマンドのテーブル、東京リージョンという今回の条件では、bulk put items の書き込み料金は、BatchWriteItem の約6分の1と試算しました。

公式ブログによると、bulk put items は専用の容量で書き込むため、テーブルの消費キャパシティのメトリクスに出ません。10万件の bulk put items 用テーブルでも、ConsumedWriteCapacityUnits は、実行中から完了の約3分後まで、1分ごとの値がすべて0でした。

まとめ

bulk put items は、S3 に置いたデータを既存のテーブルへ書き込む非同期ジョブです。100件から10万件まで、テーブルに欠落なく登録できました。

今回の測定では、完了までの時間は BatchWriteItem より長くなりました。一方で、入力ファイルを分割すると速くなり、書き込み料金は BatchWriteItem より安いという試算になりました。bulk put items の書き込みでは、テーブルの WRU を消費しませんでした。

件数が多く、完了を急がないデータの取り込みを、テーブルの WRU を消費せずに行いたい場合は、bulk put items をお試しください。

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事