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

C# 如何使用Azure在ASP.NET MVC中加速分页代码?,c#,asp.net-mvc,linq,azure,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

我正在本地开发结构中使用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);
var PageSize=25;
var qResult2=来自svc.CreateQuery(sampleTableName)中的c
其中c.PartitionKey==“samplestring”
选择c;
表存储数据服务查询表存储查询=
新表存储DataServiceQuery
(qResult2作为数据服务查询);
var result=tableStorageQuery.ExecuteAllWithRetries()
.Skip((第1页)*页面大小)
。取(页面大小);
var numberOfEntities=tableStorageQuery.ExecuteAllWithRetries().Count
ViewData[“TotalPages”]=(int)数学上限((两倍)numberOfEntities/PageSize);
ViewData[“当前页面”]=页面;
返回视图(结果);
视图使用ViewData,使用Sanderson的MVC手册中的代码计算分页链接。对于包含1000多个实体的Azure表,这是非常缓慢的。首先,“计数”需要相当长的时间来计算实体的总数。如果我正确地阅读了LINQ书籍,这是因为查询没有实现ICollection。这本书是约瑟夫·拉茨写的《临阵脱逃》

即使我将“numberOfEntities”设置为已知总数(例如1500),对于10页以上的页面,分页速度仍然很慢。我猜。跳过和/或。采取行动很慢。此外,我还调用了ExecuteAllWithRetries()两次,如果事实上Azure被查询了两次,那也没什么帮助

使用ASP.NET MVC和Azure在大型数据集中分页时应该遵循什么策略


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

Skip
Take
不是这里的问题-它们将针对
IEnumerable
执行,它已经在内存中,因此非常快

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

在表存储中,以显示的方式分页相当困难。以下是一些问题:

  • 唯一可以保证的顺序是
    分区键
    /
    行键
    顺序,因此您需要在设计
    行键时牢记这一点

  • 您可以在查询中执行
    Take
    (即您的
    qResult2
    ),因此这将减少通过连接的实体数量

  • 要执行类似于
    的跳过功能,需要使用比较运算符。因此,您需要知道您在结果集中的位置,并查询该值上方的所有
    行键
    (即,在查询中添加类似
    where c.RowKey>[lastRowKey]

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

  • 如果可能的话,另一种选择是完全取消计数。你会注意到一些大型的可扩展站点会这样做——它们没有提供页面数量的确切列表,但它们可能会让你向前/向后浏览几页。这基本上消除了计数的需要-您只需要跟踪下一页/上一页的
    行键


跳过
获取
不是这里的问题-它们将针对
IEnumerable
执行,IEnumerable已经在内存中,因此速度非常快

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

在表存储中,以显示的方式分页相当困难。以下是一些问题:

  • 唯一可以保证的顺序是
    分区键
    /
    行键
    顺序,因此您需要在设计
    行键时牢记这一点

  • 您可以在查询中执行
    Take
    (即您的
    qResult2
    ),因此这将减少通过连接的实体数量

  • 要执行类似于
    的跳过功能,需要使用比较运算符。因此,您需要知道您在结果集中的位置,并查询该值上方的所有
    行键
    (即,在查询中添加类似
    where c.RowKey>[lastRowKey]

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