AWSが提供するフルマネージドNoSQLデータベースサービスであるDynamoDBには、データ更新の方法が複数ある。DynamoDBを気軽に導入していくと、ビジネスの要求によってはDynamoDBに向かないデータ更新を選択せざるを得なくなることになってしまう。そういった状況に陥いらないためには、どのような要求が有り得るのか、もしくはどういった要求は有り得ないのかといったことを、事前に洗い出して検討しておく必要がある。また、それら要求の変化の幅に加えて、DynamoDBは何が不得意なのかを知っておく必要もある。今回は、DynamoDBの操作の中でもデータの更新処理に焦点を当てて、何が不得意なのかという事について考えることにする。
この文章は自分用の検討材料のためにまとめたものであり、内容については正確性を保つようには努めるが確実なものではない。そのため、必要にせまられてこの文章に辿りついたのであれば、実際にそれらを動かすなどして観察してみると良いと思う。その際の参考資料になれば嬉しい。
準備
DynamoDBの操作を実行するには当然DynamoDBのテーブルが必要になる。今回はAWS ConsoleからDynamoDBのテーブルを1つ作成した。またそのテーブルにアクセス可能な必要な権限をテスト用のアカウントに設定した。
(setenv "TABLE_NAME" "testing")
テスト用にいくつかのItemを事前に登録した。
aws dynamodb put-item --table-name ${TABLE_NAME} --item '{"id":{"S":"foo"},"itemType":{"N":"0"}}'
aws dynamodb put-item --table-name ${TABLE_NAME} --item '{"id":{"S":"bar"},"itemType":{"N":"1"}}'
以下のようなデータを登録した。
aws dynamodb scan --table-name ${TABLE_NAME}
{ "Items": [ { "id": { "S": "bar" }, "itemType": { "N": "1" } }, { "id": { "S": "foo" }, "itemType": { "N": "0" } } ], "Count": 2, "ScannedCount": 2, "ConsumedCapacity": null }
UpdateItem
通常DynamoDBのアイテムの更新にはUpdateItemを用いる。
aws dynamodb update-item --table-name ${TABLE_NAME} --key '{"id": {"S": "foo"}}' \
--update-expression 'SET itemType = :ok' \
--expression-attribute-values '{":ok": {"N": "1"}}'
登録したアイテムを取得してデータを確認する。
aws dynamodb get-item --table-name ${TABLE_NAME} --key '{"id": {"S": "foo"}}'
{ "Item": { "id": { "S": "foo" }, "itemType": { "N": "1" } } }
条件付きUpdateItem
UpdateItemは特定の条件を満す時にUpdateItemを実行できる。以下ではitemTypeが1の時に更新処理を行うようにしている。
aws dynamodb update-item --table-name ${TABLE_NAME} --key '{"id": {"S": "foo"}}' \
--update-expression 'SET itemType = :ng' \
--condition-expression 'itemType = :ok' \
--expression-attribute-values '{":ok": {"N": "1"}, ":ng": {"N": "0"}}'
登録したアイテムを取得してデータを確認する。
aws dynamodb get-item --table-name ${TABLE_NAME} --key '{"id": {"S": "foo"}}'
{ "Item": { "id": { "S": "foo" }, "itemType": { "N": "0" } } }
BatchWriteItem
一括でレコードを更新するのであればBatchWriteItemという方法もある。ただし以下のような制限がある。AWSのBatchWriteItemに関するドキュメントを引用する1。
If one or more of the following is true, DynamoDB rejects the entire batch write operation:
- One or more tables specified in the BatchWriteItem request does not exist.
- Primary key attributes specified on an item in the request do not match those in the corresponding table's primary key schema.
- You try to perform multiple operations on the same item in the same BatchWriteItem request. For example, you cannot put and delete the same item in the same BatchWriteItem request.
- Your request contains at least two items with identical hash and range keys (which essentially is two put operations).
- There are more than 25 requests in the batch.
- Any individual item in a batch exceeds 400 KB.
- The total request size exceeds 16 MB.
翻訳すると以下のようになる。
次の条件が1つでも当てはまる場合、DynamoDBはバッチ書き込み操作全体を拒否する。
- BatchWriteItemリクエストで存在しないテーブルがひとつでも指定された。
- リクエストのアイテムに指定された主キー属性が、対応するテーブルの主キースキーマの属性と一致しない。
- 同じBatchWriteItemリクエストの同じアイテムに対して複数の操作を実行しようとした。 同じBatchWriteItemリクエストに同じアイテムを入れたり削除したりするこ とはできない。
- リクエストには、同じハッシュキーとレンジキーを持つアイテムが少なくとも2つ含まれている。 これは基本的に2つのプット操作となる。
- バッチには25を超えるリクエストがある。
- バッチ内の個々のアイテムのサイズが400KBを超えている。
- リクエストの合計サイズが16MBを超えている。
なかなか厳しい制約がある。
PariQLを用いて複数レコードをUPDATEする
PariQLを用いたとしてもSQLのように複数レコードを一気にUPDATEはできない。ただしバッチ処理として1行ずつ更新するクエリを複数送信することで、似たようなことはできる。ただし似てはいるかもしれないが、本質的には一括更新ではないし、複数のクエリを組み立ててリクエストを送信する必要がある。