如何使用Azure加速ASP.NET MVC中的分页代码?

时间:2009-09-21 03:15:25

标签: c# asp.net-mvc linq azure

我在本地开发结构中使用ASP.NET MVC和Azure表存储。使用大型结果集时,我的分页代码非常慢:

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);

View使用ViewData来使用Sanderson的MVC书中的代码计算分页链接。对于具有1000多个实体的Azure表,这非常慢。对于初学者来说,“计数”需要相当长的时间来计算实体总数。如果我正确阅读我的LINQ书,这是因为查询没有实现ICollection。这本书是Joseph Rattz的“Pro LINQ”。

即使我将“numberOfEntities”设置为已知总数(例如1500),对于10以上的页面,分页仍然很慢。我猜测.Skip和/或.Take很慢。另外,我两次调用ExecuteAllWithRetries(),如果事实上Azure被查询了两次就无法帮助。

我应该采用什么策略来分析使用ASP.NET MVC和Azure的大型数据集?

编辑:我不需要知道确切的总页数。

1 个答案:

答案 0 :(得分:4)

SkipTake不是问题 - 它们将针对IEnumerable执行,ExecuteAllWithRetries已经在内存中,因此非常快。

PartitionKey可能是这里的罪魁祸首 - 您基本上是在此调用中从远程存储中检索分区中的所有实体,这将导致非常大的有效负载。

在表格存储中,以您展示的方式分页非常困难。以下是一些问题:

  • 唯一保证的订单是RowKey / RowKeys订单,因此您需要设计Take时考虑到这一点。

  • 您可以在查询中执行qResult2(即您的Skip),这样就可以减少通过网络传输的实体数量。

  • 要执行类似RowKeys的功能,您需要使用比较运算符。因此,您需要知道自己在结果集中的位置并查询该值之上的所有where c.RowKey > [lastRowKey](例如,在查询中添加Skip之类的内容)

  • 如果没有自己跟踪它(或者像你已经在做的那样检索整个表格),就无法检索计数。根据您的设计,您可以将计数与每个实体一起存储(即使用递增值) - 但只需确保跟踪并发编辑冲突等。如果您确实跟踪每个实体的计数,那么您也可以使用此功能执行RowKeys。另一种选择是将计数存储在另一个实体中的单个值中(您可以使用相同的表来确保事务行为)。您实际上也可以组合这些方法(将计数存储在单个实体中,以获得乐观并发,并将其存储在每个实体中,以便您知道它在哪里)。

  • 如果可能的话,另一种方法是完全摆脱计数。您会注意到有几个大型可扩展站点执行此操作 - 它们不提供有多少页面的确切列表,但它们可能会让您前进/后退几页。这基本上消除了计数的需要 - 您只需要跟踪下一个/上一页的{{1}}。