linq 分组结果需要很长时间
Posted
技术标签:
【中文标题】linq 分组结果需要很长时间【英文标题】:linq grouping result takes a long time 【发布时间】:2019-01-07 02:39:03 【问题描述】:我有以下方法可以进行一些分组
private List<CatalogVehicle> GroupResult(IEnumerable<VehicleAndQuote> vehiclesAndQuotes)
var vehicles = vehiclesAndQuotes
.GroupBy(vehicleAndQuote =>
new
vehicleAndQuote.Vehicle.VehicleMakeName,
vehicleAndQuote.Vehicle.VehicleModelTypeName,
vehicleAndQuote.Vehicle.VehicleEdition
)
.Select(a => new
vehicle = _mapper.Map<VehicleAndQuote, CatalogVehicle>(a.First()),
plans = GetLeasingpPlansGroupedByYearlyMileages(a.ToList()) //<== this one is taking ages
)
.Select(a =>
a.vehicle.LeasingPlans = a.plans;
return a.vehicle;
);
return vehicles.ToList();
以及在其中调用的方法;
private List<LeasingPlan> GetLeasingpPlansGroupedByYearlyMileages(IEnumerable<VehicleAndQuote> vehicleAndQuotes)
return vehicleAndQuotes.GroupBy(quote => quote.Quote.YearlyMileage)
.Select(group => _mapper.Map<List<VehicleAndQuote>, LeasingPlan>(group.ToList()))
.ToList();
最后一种方法需要很长时间。
IEnumerable<VehicleAndQuote> vehiclesAndQuotes
大约有 30.000 条记录。
有没有我没有看到的性能提升器?
【问题讨论】:
第二种方法结束时不调用ToList()
怎么办?您真的需要列表,还是返回IEnumerable<T>
就足够了?调用 ToList()
会创建一个全新的集合,这显然会影响性能,尤其是当元素数量开始变得足够大时。
实际上,您在查询中的所有位置都调用了ToList()
。也删除它们。
尝试在数据库端执行more。那些 ToList 造成了很多伤害。另外,尽量在SQL可翻译部分之后将automapper延迟到自己的select
@Tigran 让我试试..
该组已经实现了IEnumerable<VehicleAndQuote>
,所以你可以直接调用plans = GetLeasingpPlansGroupedByYearlyMileages(a)
。 Automapper 也接受 IEnumerable<T>
作为源。
【参考方案1】:
我正在尝试将您的查询转换为对数据库更友好的版本。
var vehicles = vehiclesAndQuotes
.GroupBy(vehicleAndQuote =>
new
vehicleAndQuote.Vehicle.VehicleMakeName,
vehicleAndQuote.Vehicle.VehicleModelTypeName,
vehicleAndQuote.Vehicle.VehicleEdition
)
.Select(a => new
// DB friendly
vehicle = a.First(),
plans = a.GroupBy(quote => quote.Quote.YearlyMileage)
)
.AsEnumerable() // May o may not be needed / passing to LINQ to Objects
.Select(a =>
var vehicle = _mapper.Map<VehicleAndQuote, CatalogVehicle>(a.vehicle);
var plans = a.plans.Select(group => _mapper.Map<IEnumerable<VehicleAndQuote>, LeasingPlan>(group));
vehicle.LeasingPlans = plans;
return vehicle;
);
return vehicles.ToList(); // This should be avoided, specially if you are processing a large collection.
通过这种方式,您可以在数据库端进行双重分组。另外,我直到最后才实现整个系列。
希望这会有所帮助!
【讨论】:
thnx,但这根本不在数据库中......还有其他想法......? 没想到会编译,我只是在***编辑器上复制编辑了;-) @RoelantM 如果数据库不适合,那么您的代码版本非常接近获取所需数据的最佳方式。为了更好的事情,你需要从根本上改变你正在做的事情。 附加理想:使用并行加速加载和分组等 有些语句在最后一个 Select 中没有以分号结束。已更正。【参考方案2】:在SQL Profiler
中检查生成的查询。您的查询正在对vehicle
和plans
中的每条记录(N+1 problem)
进行选择。如果您使用Entity Framework 2.0
,您应该知道它在本地运行GroupBy
,并像SELECT *
一样将数据库中的所有数据提取到内存中,然后将它们分组到内存中。将您的查询分解为每个实体的多个查询。不要在您的Select
LINQ 函数中使用LINQ
之类的First()
函数,因为它会导致N+1 SQL Issue
。将您的 EF 版本升级到 2.1 或更高版本以避免Local GroupBy
问题。
【讨论】:
抱歉,我没有看到 IEnumerable以上是关于linq 分组结果需要很长时间的主要内容,如果未能解决你的问题,请参考以下文章
CoreData - 删除所有实体消耗 RAM 并需要很长时间
调用 Web Service Async-methods 需要很长时间才能返回结果如何处理