我正在使用LINQ在我的控制器中准备一些数据并将它们发送到视图中。 我的连接由EF6代码首次与sql server迁移 所以在控制器和LINQ表达式中,数据库模型映射到正确的视图模型如下:
var temp = db.points.ToList().Select(pnt => new MapPointsModel()
{
pointId = pnt.pointId,
name = pnt.name,
positionX = pnt.positionX,
positionY = pnt.positionY,
road = pnt.road.id,
order = pnt.order,
signalState = pnt.signalState,
powerState = pnt.powerState,
videoState = pnt.videoState,
cameraState = pnt.cameraState,
hourTraffic = new int[]{
pnt.crossings.Where(c => DateTime.Compare(c.dateTime, lastHour) >= 0 ).Where(c => c.line == 1).Count(),
pnt.crossings.Where(c => DateTime.Compare(c.dateTime, lastHour) >= 0 ).Where(c => c.line == 2).Count(),
pnt.crossings.Where(c => DateTime.Compare(c.dateTime, lastHour) >= 0 ).Where(c => c.line == 3).Count()
},
dayTraffic = new int[]{
pnt.crossings.Where(c => DateTime.Compare(c.dateTime, lastDay) >= 0 ).Where(c => c.line == 1).Count(),
pnt.crossings.Where(c => DateTime.Compare(c.dateTime, lastDay) >= 0 ).Where(c => c.line == 2).Count(),
pnt.crossings.Where(c => DateTime.Compare(c.dateTime, lastDay) >= 0 ).Where(c => c.line == 3).Count()
},
hourViolation = new int[] {
pnt.crossings.Where(c => c.violation != null && DateTime.Compare(c.dateTime, lastHour) >= 0).Where(c => c.line == 1).Count(),
pnt.crossings.Where(c => c.violation != null && DateTime.Compare(c.dateTime, lastHour) >= 0).Where(c => c.line == 2).Count(),
pnt.crossings.Where(c => c.violation != null && DateTime.Compare(c.dateTime, lastHour) >= 0).Where(c => c.line == 3).Count()
},
dayViolation = new int[] {
pnt.crossings.Where(c => c.violation != null && DateTime.Compare(c.dateTime, lastDay) >= 0).Where(c => c.line == 1).Count(),
pnt.crossings.Where(c => c.violation != null && DateTime.Compare(c.dateTime, lastDay) >= 0).Where(c => c.line == 2).Count(),
pnt.crossings.Where(c => c.violation != null && DateTime.Compare(c.dateTime, lastDay) >= 0).Where(c => c.line == 3).Count()
},
checkedViolations = pnt.crossings.Where(c => c.violation != null).Where(c => c.violation.deliberated == true).Count(),
uncheckedViolations = pnt.crossings.Where(c => c.violation != null).Where(c => c.violation.deliberated == false).Count(),
bandAvgSpeed = new int[] {
pnt.crossings.Where(c => c.line == 1).Count() == 0 ? 0 : pnt.crossings.Where(c => c.line == 1).Sum(c => c.speed)/pnt.crossings.Where(c => c.line == 1).Count(),
pnt.crossings.Where(c => c.line == 2).Count() == 0 ? 0 : pnt.crossings.Where(c => c.line == 2).Sum(c => c.speed)/pnt.crossings.Where(c => c.line == 2).Count(),
pnt.crossings.Where(c => c.line == 3).Count() == 0 ? 0 : pnt.crossings.Where(c => c.line == 3).Sum(c => c.speed)/pnt.crossings.Where(c => c.line == 3).Count(),
},
});
return temp.ToList();
此代码适用于10000条或更低的记录,但是在500000条或更多条记录中没有结果,并且在所有测试中都超时有效。
我正在寻找这个问题的原因
的
“点数”表中只有4条记录,超过500000条记录的较大记录是“交叉点”但是我尝试从.toList()
删除db.points
来解决问题,但它上升了例外:
System.ArgumentException: Argument types do not match
的
答案 0 :(得分:2)
你的问题是:
db.points.ToList()....
这将从表中检索所有记录到内存中。因此,您拥有的记录越多,所需的时间就越长。您需要创建一个只返回所需记录的查询。
我不确定你打算一次性使用500,000条记录。你只需要一个子集吗?如果是这样,那么做这样的事情:
db.points.Select(....).Take(25) // or however many you need.
您还在进行大量的子选择和子计数,每个子计数都是单独的语句,因此对于那些500,000,您实际上可能有数百万个子查询。
答案 1 :(得分:0)
您正在将其转换为List。这一直在占用。尝试从db.points.ToList()中删除ToList()。选择。这应该可以解决你的问题。
在使用ToList转换它之前,它仍然是IQueryable并且不会命中数据库。当你执行ToList时,它将查询数据库,在内存中获取结果,然后处理内存中的记录。
答案 2 :(得分:0)
这样做
var temp = db.points.ToList()....
将整个表格带到客户端,所以如果你有几兆的数据,这可能需要一段时间,具体取决于cpu /连接/内存
答案 3 :(得分:0)
您需要更改代码中的ToList()
并更改var temp = db.points.AsNoTracking()
这样可以节省您的时间。另外,为您的代码创建预先生成的视图,可以提供更好的性能。
答案 4 :(得分:0)
主要问题是平均!!!
因为平均函数在所有记录上运行4次,所以大约需要7秒。
我更改了linq查询,而不是一次请求所有数据,而是使用OrderBy GroupBy工具从服务器的其他请求中计算的平均部分。然后合并两个从服务器检索的列表。
此外,我从points表中移除了.ToList()(如人们建议的那样)并将数组结构更改为简单变量(这导致了错误!)。
此解决方案导致运行时间仅为1秒而不是7秒,具有相同的输出:)