Table Storage でバッチ処理

Azure の Table Storage を .NET から扱う場合は Microsoft.WindowsAzure.Storage 1 が利用できる。その中でバッチ処理についてメモ。

単一のテーブルにバッチ処理を行いたい場合は TableBatchOperation クラスを使う。

var entities = GetEntities();
var operations = new TableBatchOperation();
foreach(var entity in entities)
{
    operations.Add(TableOperation.Add(entity));
}
await table.ExecuteBatchAsync(operations, cancellationToken);

Atomicity は担保されているらしい。なので 1 件でも失敗したらロールバックされるような動きになる。 参考

パフォーマンスもこの方がいいらしい。

また TableBatchOperationIList<T> の実装なので実行順序は保証されている。はず。よね?

注意しときたいのは、このとき entities が空だと ExecuteBatchAsync で空振り......ではなく StorageException を吐く。 TableBatchOperation にオペレーションを詰める前に分岐させてスキップしておくのが良さげ。

var entities = GetEntities();
if(entities.Length > 0)
{
    var operations = new TableBatchOperation();
    foreach(var entity in entities)
    {
        operations.Add(TableOperation.Add(entity));
    }
    await table.ExecuteBatchAsync(operations, cancellationToken);
}

また、 1 バッチオペレーションでは Insert / Delete 同時に実行できるが、同一エンティティを Insert / Delete しようとすると死ぬ。意図的にこんなことをしようとすることはないだろうけど、結果的にそうなっちゃったってことは起こり得るかも。

try
{
    var operation = new TableBatchOperation
    {
        TableOperation.Insert(new UserMappingSet {PartitionKey = "hoge", RowKey = "fuga"}), 
        TableOperation.Delete(new UserMappingSet {PartitionKey = "hoge", RowKey = "fuga", ETag = "*"})
    };  
    await table.ExecuteBatchAsync(operation, cancellationToken);
}
catch (StorageException ex)
{
    // "1:One of the request inputs is not valid. ..."
    log.Error(e.RequestInformation.ExtendedErrorInformation.ErrorMessage)
}

なお複数テーブルに対するトランザクション処理的なものは用意されていない。 Entity Group Transactions というのが使えそうな気配がするが、少なくとも SDK にそれっぽいものがなく、 REST API 専用なのかな?


  1. .NET を使用して Azure Table Storage と Azure Cosmos DB Table API を使用する | Microsoft Docs によると 「 Microsoft.Azure.Storage.Common を使え」らしいが、 NuGet で落とそうとすると preview しかなかったりして謎。