在我的程序中,我从MySQL数据库中复制数据,理论上我正在通过分页来减少结果集。对于具有大约25列数据的30行数据,似乎需要花费很长时间600-800毫秒,而每个单元中没有任何非常大的数据。
这是否只是通过点击数据库来检索数据而导致的性能损失?我经常更新这些数据,它是每个用户不同的数据集,因此我无法将其缓存或预加载到内存中。
我希望能有一些关于如何离开这里的建议。我看了制作一个单独的存储过程来为我的分页进行总计数,但主要的点击似乎是我必须将数据复制到程序到列表然后为我的网页视图生成JSON。
我对此有点新意见,我认为我的前端页面的响应能力因为产生这些结果所花费的时间而开始受到影响。 1.8 - 2.5秒的页面刷新似乎太长了,无法重新加载显示30个结果的网格。
提前谢谢你。
编辑: 其他细节:
表中的所有主键都已编制索引。是的我已经分析了花费最长时间的EF查询,它似乎没有做任何更多的分页选择。实施例
sql = "System.Collections.Generic.List`1[PeerTrader.usercollectionenhancedview].OrderBy(Param_0 => Param_0.CardName).Skip(90).Take(30)"
我们可以将客户端排除在外,因为我在我的控制器上测量诊断,基本上客户端没有为显示器的显示添加任何实际开销。基本上,准备JSon数据以将其返回给客户端所花费的时间是相同的。
一般来说,这个页面通常为30(尽管从存储过程中将其减少到行数为5时,它所用的时间并没有真正改变),结果总计数约为20K。
实际命中是我实际上从数据库“读取”数据。因此,无论我在哪里注入实际加载来自数据库的结果,这似乎是最大的打击。运行应该模拟我的服务器在MySQL服务器上进行的页面调用的分页查询返回60毫秒的结果。
这是我的控制器操作:在下面的示例中,我将整个数据集复制到过滤器后面的List,因为天气似乎并不重要,我会复制5,30或20K行,它在读取操作中似乎是相同的命中,然后它允许我稍后在控制器中枚举数据集。
public ActionResult GridData(string sidx, string sord, int page, int rows, bool _search, string filters)
{
///**********Diagnostics Start********
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
///**********Diagnostics End********
MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
int currentUserID = (int)currentUser.ProviderUserKey;
var serializer = new JavaScriptSerializer();
//Filters f = (!_search || string.IsNullOrEmpty(filters)) ? null : serializer.Deserialize<Filters>(filters);
Filters_IQueryable f = (!_search || string.IsNullOrEmpty(filters)) ? null : serializer.Deserialize<Filters_IQueryable>(filters);
IQueryable<usercollectionenhancedview> query = db.SingleUserCollectionView(currentUserID).AsQueryable();
var filteredQuery = (f == null ? query : f.FilterObjectSet(query)).ToList();
///**********Diagnostics Start********
sw.Stop(); long t1 = sw.ElapsedMilliseconds; sw.Start();
System.Diagnostics.Debug.WriteLine("");
System.Diagnostics.Debug.WriteLine("**************");
System.Diagnostics.Debug.WriteLine("T1: " + t1);
///**********Diagnostics End********
int totalRecords;
totalRecords = filteredQuery.Where(x => x.fk_IdUsers == currentUserID).Count();
pagedQuery = filteredQuery.AsQueryable().Where(x => x.fk_IdUsers == currentUserID).OrderBy(sidx + " " + sord).Skip((page - 1) * rows).Take(rows);
///**********Diagnostics Start********
sw.Stop(); long t2 = sw.ElapsedMilliseconds; sw.Start();
System.Diagnostics.Debug.WriteLine("T2: " + t2);
///**********Diagnostics End********
我希望我已经添加了足够的额外信息以供进一步评论,如果不是让我知道。我很感激你对我的问题的探索。
编辑2:
sql = "System.Data.Objects.ObjectResult
1 [PeerTrader.usercollectionenhancedview] .OrderBy(Param_0 =&gt; Param_0.CardName).Skip(0).Take(30)“When I go looking on my DB, the actual call on the DB to do the
order by`实际上有点相当时间,实际数据库本身300毫秒,所以看起来我跟踪了一个昂贵的下降
答案 0 :(得分:0)
var filteredQuery = (f == null ? query : f.FilterObjectSet(query)).ToList();
以上线看起来很可疑。见here:
ToList(IEnumerable)方法强制立即进行查询评估
如果您只需要一个计数和30个项目,则无需实现1000个结果。应重写以下查询以对数据库进行操作,而不是物化集合。使用count()和Skip()时生成的SQL.Take()应足以将结果限制为仅需要的结果但您可能希望使用ObjectQuery.ToTraceString()
检查实际查询
totalRecords = filteredQuery.Where(x => x.fk_IdUsers == currentUserID).Count();
pagedQuery = filteredQuery.AsQueryable().Where(x => x.fk_IdUsers == currentUserID)
.OrderBy(sidx + " " + sord).Skip((page - 1) * rows).Take(rows);
如果您仍然遇到问题而且这是一种只读情况,您可以尝试使用.AsNoTracking()
并关闭代理生成。