1

ローカル開発ファブリックで ASP.NET MVC と Azure Table Storage を使用しています。大きな結果セットを操作すると、ページネーション コードが非常に遅くなります。

var PageSize = 25;
var qResult2 = from c in svc.CreateQuery<SampleEntity>(sampleTableName)
                           where c.PartitionKey == "samplestring"
                           select c;
TableStorageDataServiceQuery<SampleEntity> tableStorageQuery = 
                 new TableStorageDataServiceQuery<SampleEntity>
                 (qResult2 as DataServiceQuery<SampleEntity>);
var result = tableStorageQuery.ExecuteAllWithRetries()
                                .Skip((page - 1) * PageSize)
                                .Take(PageSize);
var numberOfEntities = tableStorageQuery.ExecuteAllWithRetries().Count
ViewData["TotalPages"] = (int)Math.Ceiling((double) numberOfEntities / PageSize);
ViewData["CurrentPage"] = page;
return View(result);

ViewData は、Sanderson の MVC ブックのコードを使用してページング リンクを計算するために View によって使用されます。1000 以上のエンティティを持つ Azure テーブルの場合、これは非常に遅くなります。まず、「Count」はエンティティの総数を計算するのにかなりの時間がかかります。LINQ ブックを正しく読んでいる場合、これはクエリが ICollection を実装していないためです。その本は、ジョセフ・ラッツによる「Pro LINQ」です。

"numberOfEntities" を既知の合計 (たとえば 1500) に設定しても、ページングは​​ 10 を超えるページではまだ遅いです。.Skip や .Take が遅いと推測しています。また、私は ExecuteAllWithRetries() を 2 回呼び出しますが、実際に Azure が 2 回クエリされた場合、それは役に立ちません。

ASP.NET MVC と Azure を使用して大規模なデータセットをページングするには、どのような戦略に従う必要がありますか?

編集: 正確な総ページ数を知る必要はありません。

4

1 に答える 1

4

Skipここでは問題ではありTakeません-それらは に対して実行されますIEnumerable。これはすでにメモリ内にあるため、非常に高速です。

ExecuteAllWithRetriesが原因である可能性があります。この呼び出しでは、基本的にパーティション内のすべてのエンティティをリモート ストレージから取得しているため、ペイロードが非常に大きくなります。

あなたが示している方法でのページネーションは、Table Storage では非常に困難です。ここにいくつかの問題があります:

  • 保証される唯一の順序はPartitionKey/の順序であるため、これを念頭に置いRowKeyて設計する必要があります。RowKeys

  • Takeクエリでを実行できるため(つまり、 qResult2)、ネットワークを経由するエンティティの数を減らすことができます。

  • のような機能を実行するSkipには、比較演算子を使用する必要があります。そのため、結果セットのどこにいるのかを把握し、RowKeysその値より上にクエリを実行する必要があります (つまり、where c.RowKey > [lastRowKey]クエリに次のようなものを追加します)。

  • 自分で追跡せずにカウントを取得する方法はありません (または、既に行っているようにテーブル全体を取得します)。設計によっては、各エンティティと共にカウントを保存することもできます (つまり、増分値を使用します) - ただし、同時編集の競合などを追跡するようにしてください。各エンティティのカウントを追跡する場合は、これを使用して実行することもできますSkip。別のオプションは、カウントを別のエンティティの単一の値に格納することです (同じテーブルを使用して、トランザクションの動作を保証できます)。これらのアプローチを実際に組み合わせることもできます (カウントを 1 つのエンティティに格納して、楽観的な同時実行性を取得し、各エンティティに格納して、それがどこにあるかを確認します)。

  • 別の方法は、可能であれば、カウントを完全に取り除くことです。いくつかの大規模なスケーラブルなサイトがこれを行っていることに気付くでしょう - それらはページ数の正確なリストを提供しませんが、数ページ前後に移動できる場合があります. RowKeysこれにより、基本的にカウントの必要がなくなります。次/前のページを追跡するだけで済みます。

于 2009-09-21T04:29:57.850 に答える