13

1 つのバッチで 2 つの行を取得するように設計された TableBatchOperation を初期化するコードを次に示します。

 TableBatchOperation batch = new TableBatchOperation();
 batch.Add(TableOperation.Retrieve("somePartition", "rowKey1"));
 batch.Add(TableOperation.Retrieve("somePartition", "rowKey2")); 
 //second call throws an ArgumentException:
 //"A batch transaction with a retrieve operation cannot contain 
 //any other operation"

前述のように、例外がスローされ、単一のバッチで N 行を取得することはサポートされていないようです。リクエストごとに約 50 行を取得する必要があるため、これは私にとって大きな問題です。この問題は、コスト面と同じくらいパフォーマンス面でも重要です。ご存知かもしれませんが、Azure Table Storage の価格はトランザクションの量に基づいています。つまり、50 回の取得操作は、1 回のバッチ操作よりも 50 倍の費用がかかります。

私は何かを逃しましたか?

余談 ですが、私は新しい Azure Storage API 2.0 を使用しています。この質問が Web 上で提起されたことがないことに気付きました。この制約は最近追加された可能性がありますか?

編集

ここで関連する質問を見つけました: Azure Table Storage Query on PartitionKey/RowKey List で非常に遅い。行キーに「または」を指定して TableQuery を使用すると、完全なテーブル スキャンが行われるようです。ここには本当に深刻な問題があります...

4

7 に答える 7

5

Azure Table Storage (ATS) でパーティション キー (PK) と行キー (RK) スキームを設計するときは、データを取得する方法を第一に考慮する必要があります。あなたが言ったように、実行する各クエリには両方の費用がかかりますが、さらに重要なことに時間がかかるため、1 つの効率的なクエリですべてのデータを取得する必要があります。ATS で実行できる効率的なクエリには、次の種類があります。

  • 正確な PK と RK
  • 正確な PK、RK 範囲
  • PK 範囲
  • PKレンジ、RKレンジ

あなたのコメントに基づいて、次のようなデータがあると思います。

PK    RK     Data
Guid1 A      {Data:{...}, RelatedRows: [{PK:"Guid2", RK:"B"}, {PK:"Guid3", RK:"C"}]}
Guid2 B      {Data:{...}, RelatedRows: [{PK:"Guid1", RK:"A"}]
Guid3 C      {Data:{...}, RelatedRows: [{PK:"Guid1", RK:"A"}];}

Guid1 でデータを取得したので、次に Guid2 と Guid3 を読み込む必要があります。また、これらの行はすべて同じユーザーのものであるため、共通の分母はないと推測しています。これを念頭に置いて、次のような追加の「インデックス テーブル」を作成します。

PK      RK      Data
Guid1-A Guid2-B {Data:{....}}
Guid1-A Guid3-C {Data:{....}}
Guid2-B Guid1-A {Data:{....}}
Guid2-B Guid1-A {Data:{....}}

ここで、PK は親の PK と RK の組み合わせであり、RK は子行の PK と RK の組み合わせです。次に、PK="Guid1-A" ですべての行を返すというクエリを実行すると、1 回の呼び出し (または全体で 2 回の呼び出し) ですべての関連データを取得できます。これが作成する最大のオーバーヘッドは書き込みにあるため、行を右に移動するときに、関連する行ごとに行を書き込む必要があり、データが最新の状態に保たれていることを確認する必要があります (これは問題にならない場合があります)。これが 1 回のみの書き込みのシナリオである場合)。

私の仮定のいずれかが間違っている場合、またはサンプル データがある場合は、この回答をより関連性の高い例で更新できます。

于 2013-01-08T03:33:25.577 に答える
4

次のようなことを試してください:

TableQuery<DynamicTableEntity> query = new TableQuery<DynamicTableEntity>()
                                                .Where(TableQuery.CombineFilters(
                                                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "partition1"),
                                                    TableOperators.And,
                                                    TableQuery.CombineFilters(
                                                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "row1"),
                                                        TableOperators.Or,
                                                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "row2"))));
于 2013-09-16T20:55:05.687 に答える
3

これは古い質問であることは承知していますが、Azure はまだセカンダリ インデックスをサポートしていないため、しばらくは関連があるようです。

私は同じタイプの問題にぶつかっていました。私のシナリオでは、何百万もの行がある同じパーティション内で何百ものアイテムを検索する必要がありました (GUID を行キーとして想像してください)。10,000行を検索するためのいくつかのオプションをテストしました

  1. (PK && RK)
  2. (PK && RK1) || (PK & RK2) || ...
  3. PK && (RK1 || RK2 || ... )

最大 10 度の並列処理 (最大 10 個の未処理のリクエスト) で Async API を使用していました。また、いくつかの異なるバッチ サイズ (10 行、50、100) もテストしました。

Test                        Batch Size  API calls   Elapsed (sec)
(PK && RK)                  1           10000       95.76
(PK && RK1) || (PK && RK2)  10          1000        25.94
(PK && RK1) || (PK && RK2)  50          200         18.35
(PK && RK1) || (PK && RK2)  100         100         17.38
PK && (RK1 || RK2 || … )    10          1000        24.55
PK && (RK1 || RK2 || … )    50          200         14.90
PK && (RK1 || RK2 || … )    100         100         13.43

注意: これらはすべて同じパーティション内にあります - 複数の行キーだけです。

API 呼び出しの数を減らすだけでよかったのに。しかし、追加の利点として、経過時間も大幅に短縮され、計算コストが節約されます (少なくとも私の場合は!)。

当然のことながら、100 行のバッチが最高の経過パフォーマンスを実現しました。明らかに他のパフォーマンスに関する考慮事項、特にネットワークの使用があります (たとえば、#1 はネットワークをほとんど使用しませんが、他の人はネットワークをより強く使用します)。

編集 多くの行キーを照会するときは注意してください。クエリには (もちろん) URL の長さ制限があります。この長さを超えても、サービスは URL が切り捨てられたことを認識できないため、クエリは成功します。私たちの場合、結合されたクエリの長​​さを約 2500 文字 (URL エンコード!) に制限しました。

于 2016-05-29T19:08:36.993 に答える
0

パーティションごとにいくつのエンティティがありますか? 1 回の取得操作で、クエリごとに最大 1000 レコードを取得できます。次に、メモリ内セットで行キー フィルタリングを実行し、1 回の操作に対してのみ支払うことができます。

もう 1 つのオプションは、行キー範囲クエリを実行して、1 回の操作でパーティションの一部を取得することです。基本的に、パーティション全体ではなく、返される行キーの上限と下限を指定します。

于 2013-01-07T13:59:51.947 に答える
0

あなたの最善の策は、探しているものを取得する Linq/OData 選択クエリを作成することです。

パフォーマンスを向上させるには、パーティションごとに 1 つのクエリを作成し、それらのクエリを同時に実行する必要があります。

私はこれを個人的にテストしていませんが、うまくいくと思います。

于 2013-01-07T13:13:35.893 に答える