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&lt;VehicleAndQuote&gt; vehiclesAndQuotes 大约有 30.000 条记录。 有没有我没有看到的性能提升器?

【问题讨论】:

第二种方法结束时不调用ToList()怎么办?您真的需要列表,还是返回IEnumerable&lt;T&gt; 就足够了?调用 ToList() 会创建一个全新的集合,这显然会影响性能,尤其是当元素数量开始变得足够大时。 实际上,您在查询中的所有位置都调用了ToList()。也删除它们。 尝试在数据库端执行more。那些 ToList 造成了很多伤害。另外,尽量在SQL可翻译部分之后将automapper延迟到自己的select @Tigran 让我试试.. 该组已经实现了IEnumerable&lt;VehicleAndQuote&gt;,所以你可以直接调用plans = GetLeasingpPlansGroupedByYearlyMileages(a)。 Automapper 也接受 IEnumerable&lt;T&gt; 作为源。 【参考方案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 中检查生成的查询。您的查询正在对vehicleplans 中的每条记录(N+1 problem) 进行选择。如果您使用Entity Framework 2.0,您应该知道它在本地运行GroupBy,并像SELECT * 一样将数据库中的所有数据提取到内存中,然后将它们分组到内存中。将您的查询分解为每个实体的多个查询。不要在您的Select LINQ 函数中使用LINQ 之类的First() 函数,因为它会导致N+1 SQL Issue。将您的 EF 版本升级到 2.1 或更高版本以避免Local GroupBy 问题。

【讨论】:

抱歉,我没有看到 IEnumerable np,有什么想法吗?

以上是关于linq 分组结果需要很长时间的主要内容,如果未能解决你的问题,请参考以下文章

结果集需要很长时间来处理来自 Oracle 的大数据

CoreData - 删除所有实体消耗 RAM 并需要很长时间

调用 Web Service Async-methods 需要很长时间才能返回结果如何处理

svm 需要很长时间进行超参数调整

如果使用 ORDER BY String Column,MySQL 查询需要很长时间才能执行

在 MYSQL 表上选择查询需要很长时间并超时