初級読了 2 分

DynamoDBで複数のアイテムを削除する方法

DynamoDBにDELETE FROM table WHERE …はありません。すべての削除は完全なプライマリキーで1つのアイテムを対象にします — APIには一括削除操作もtruncateもなく、DELETE文もステートメントごとにちょうど1つのアイテムしか削除しません。つまり「複数のアイテムを削除する」は常に2ステップの作業です:キーを見つけ、次にキーごとに1つの削除を発行し、スループットのためにバッチ化します。

このガイドでは、バッチ化の選択肢、all-or-nothingのトランザクション版、すべてを削除するケース、そしてGUIで選択と2つのキーストロークだけで同じことを行う方法を扱います。

DynamoDBで複数のアイテムを削除するには?

削除したいアイテムのプライマリキーを(QueryまたはScanで)集め、バッチで削除します:BatchWriteItemは1回の呼び出しで最大25個のDeleteRequestを受け取り、TransactWriteItemsは最大100アイテムをアトミックに削除し、PartiQLのDELETE文はBatchExecuteStatementで25個ずつバッチ実行できます。DynoTableでは行を選択して⌘⌫を押して削除をステージし、レビューしてコミットします。

  • 一括・ベストエフォート: BatchWriteItem — 1回の呼び出しで25削除、残りはリトライ。
  • All-or-nothing: TransactWriteItems — 一緒に成功するか一緒に失敗する最大100のアクション。
  • SQL風の構文: PartiQL DELETE + BatchExecuteStatement — キーごとのルールは同じ、綴りが馴染み深いだけ。
  • テーブル内のすべて: truncate戦略 — 通常はテーブルを削除して再作成するほうが安上がり。
  • 視覚的な選択: DynoTableでのステージ削除 — 行を選択、ステージ、赤い差分をレビュー、コミット。

ステップ0:キーを集める

削除にはプライマリキー全体が必要です — テーブルではパーティションキー_と_ソートキーです (AWS: 「各プライマリキーについて、_すべて_のキー属性を指定する必要があります」)。任意の属性で削除することはできないので、「status = 'archived'のすべてのアイテムを削除する」は読み取りから始まります:

  • 条件がキー(またはGSIのキー)にあるなら、対象を絞ったQueryで安価にキーを集められます。
  • そうでなければフィルタ付きのScanです — フィルタの有無にかかわらず、テーブル全体を読み取り(そして課金し)ます。query vs scanを参照してください。

キー属性だけを返すProjectionExpressionを使い、LastEvaluatedKeyを最後まで辿ってください(ページネーション)。さもないと最初の1 MBページ分だけを黙って削除することになります。

方法1:BatchWriteItem(1回の呼び出しで最大25削除)

BatchWriteItemは1回の呼び出しで最大25個のput/deleteリクエスト、または16 MBをまとめます (AWS APIリファレンス: 「BatchWriteItemへの単一の呼び出しは、最大25個のアイテムのputまたはdelete操作からなる、最大16MBのデータをネットワーク経由で送信できます」)。

aws dynamodb batch-write-item --request-items '{
  "Orders": [
    {"DeleteRequest": {"Key": {"PK": {"S": "ORDER#1001"}, "SK": {"S": "META"}}}},
    {"DeleteRequest": {"Key": {"PK": {"S": "ORDER#1002"}, "SK": {"S": "META"}}}},
    {"DeleteRequest": {"Key": {"PK": {"S": "ORDER#1003"}, "SK": {"S": "META"}}}}
  ]
}'

バッチの3つの性質が人をつまずかせます — すべて APIリファレンス そのままです:

  • アトミックではありません。BatchWriteItemで指定された個々のPutItemおよびDeleteItem操作はアトミックですが、BatchWriteItem全体としてはアトミックではありません。」一部の削除が成功し、他が失敗することがあります。
  • UnprocessedItemsをリトライしなければなりません。 スロットリングされたリクエストは、リクエストと同じ形でUnprocessedItemsレスポンスマップに返ってきます —「通常、BatchWriteItemはループで呼び出します」、そしてAWSはリトライの間に「指数バックオフアルゴリズムの使用を強く推奨」しています。
  • 条件は使えません。「個々のputおよびdeleteリクエストに条件を指定することはできません」— 条件付き削除は代わりにDeleteItemかトランザクションを通す必要があります。バッチはまた、1回の呼び出しで同じキーに対する2つの操作を拒否します。

ループの形 — 25個ずつに分割、送信、残りをバックオフ付きで再キュー — は バッチ操作で扱っているものと同じです。

方法2:TransactWriteItems(アトミックな削除)

一連の削除が一緒に成功または失敗しなければならないとき — 例えば親アイテムとそのの子を削除する場合 — はTransactWriteItemsを使います:最大100アクション(削除、put、更新、条件チェック)がアトミックに適用され、アイテムごとのも使えます。トレードオフ:トランザクション書き込みはプレーンな書き込みの2倍の書き込みキャパシティがかかります。完全な仕組み(冪等性トークン、TransactionCanceledException、コスト計算)は DynamoDBトランザクションにあります。

方法3:PartiQL DELETEのバッチ実行

PartiQLはキーごとのルールを取り除きません — 綴り直すだけです。開発者ガイドは明示的です (PartiQL DELETE): 「一度に削除できるのは1つのアイテムだけです。複数のアイテムを削除する単一のDynamoDB PartiQLステートメントを発行することはできません」、そしてWHERE条件は「単一のプライマリキー値に解決されなければなりません」。

複数のアイテムを削除するには、単一アイテムのステートメントをバッチ化します — BatchExecuteStatement は1バッチあたり最大25ステートメントを実行します(すべて読み取りかすべて書き込みで、混在は不可):

[
  {"Statement": "DELETE FROM \"Orders\" WHERE PK = 'ORDER#1001' AND SK = 'META'"},
  {"Statement": "DELETE FROM \"Orders\" WHERE PK = 'ORDER#1002' AND SK = 'META'"}
]
aws dynamodb batch-execute-statement --statements file://statements.json

完全なキーを固定しないWHEREは失敗します — DELETE FROM Orders WHERE status = 'archived'は存在しません。その他のPartiQLパターン(とその背後にある制限)はPartiQLの例PartiQL vs SQLにあります。

すべてのアイテムを削除する(truncate)

DynamoDBにtruncateはありません。選択肢を推奨順に:

  1. テーブルを削除して再作成する。 テーブル全体をアイテム単位で削除するとアイテムごとに1書き込みが課金されます。DeleteTable + CreateTableは書き込み料金全体を回避します。落とし穴:テーブル設定 — インデックス、TTL、、キャパシティモード、タグ — は勝手には戻ってきません。作成時に再宣言します(infrastructure-as-codeならこれは何でもないことです)。
  2. でアイテムを失効させる。 本当に欲しいのが「Xより古いものをすべて削除」なら、TTL書き込みキャパシティを消費せずに期限切れアイテムをバックグラウンドで削除します — 何のコストもかからない、スローモーションの一括削除です。
  3. Scan + バッチ削除(方法1)は、テーブルを稼働させたまま一部だけを消す場合です — スキャンしたアイテムごとの読み取りと、削除したアイテムごとの書き込みを支払います。

DynoTableで複数のアイテムを削除する

上記の選択して削除するフロー — クエリ、キー収集、分割、リトライ — は、まさにGUIが引き受けるべき雑務です。DynoTableではグリッドの選択です:

  1. 消したい行が画面に表示されるように、クエリを実行またはフィルタします。
  2. 行を選択して⌘⌫を押します — 選択したすべての行がステージされた削除になります。まだDynamoDBには何も触れていません:行はグリッドで赤く色づき、ステージングパネルにレビュー可能なカードとして表示されます。
  3. レビューしてコミットします。コミットは楽観ロックの条件付きのTransactWriteItemsバッチとして送信され — ステージされた削除はアイテムがまだ存在する場合にのみ実行されます — 大きなステージはDynamoDBのトランザクション制限内に収まるよう自動的に分割されます。⌘⇧⌫はレビューをスキップし、1つのコードで選択の削除とコミットを行います。
DynoTableでのステージされた削除:選択された行がグリッドで赤く色づき、コミット前にそれぞれがステージングパネルのレビュー可能なカードになっているところ。
DynoTableでのステージされた削除:選択された行がグリッドで赤く色づき、コミット前にそれぞれがステージングパネルのレビュー可能なカードになっているところ。

スコープは正直です:削除するのは選択した行 — レビュー済みで、コミットまでは取り消せる操作 — であって、盲目的なテーブル全体のtruncateではありません。テーブル全体を消すなら、削除して再作成してください(上記)。

削除に手書きの条件(attribute_exists、バージョンチェック)が必要なら、 DynamoDB Expression Builderで正確なConditionExpression+プレースホルダーマップを組み立てて、代わりにDeleteItemやトランザクションに付けてください。

FAQ

DynamoDBの1回の呼び出しで複数のアイテムを削除できますか? はい — BatchWriteItemで最大25個(ベストエフォート、UnprocessedItemsをリトライ)、またはTransactWriteItemsでアトミックに最大100個です。どちらもアイテムごとに完全なプライマリキーが必要で、アイテムを選択する「where」条件はどちらも受け付けません。

DynamoDBにDELETE WHEREはありますか? ありません。低レベルAPIもPartiQLも条件による削除はできません — PartiQLのDELETEは「単一のプライマリキー値に解決される」WHEREを要求します。まずキーをクエリまたはスキャンで集めてから、1つずつ削除します。

DynamoDBテーブルのすべてのアイテムを削除するには? 完全に消すなら、テーブルを削除して再作成します — アイテムごとに1書き込みを支払わずに済みます。経過時間ベースのクリーンアップにはTTLを使ってください。書き込みキャパシティを消費せずに期限切れアイテムを削除します。テーブルを稼働させたままにする必要があるときのフォールバックがScan+バッチ削除です。

バッチ削除の後にアイテムが再出現するのはなぜですか? ほとんどの場合、リトライされていないUnprocessedItemsです:スロットリングされたBatchWriteItemは失敗した削除をレスポンスの中に黙って返し、それをループしないコードは、アイテムがまだテーブルに残ったまま「完了」します。マップが空で返ってくるまで指数バックオフでリトライしてください。

アイテムの削除にはいくらかかりますか? 各削除は標準の書き込み(1 KBあたり1 WCU、トランザクション内では2倍)で、キーを見つけるのにも読み取りコストがかかります。料金計算ツールで被害額を見積もってください。

まず何を削除するのか見てから消したいですか?DynoTableをダウンロードしてください — 行を選択し、⌘⌫で削除をステージし、差分をレビューし、確信できたらコミットします。

更新日