【问题标题】:linq grouping result takes a long timelinq 分组结果需要很长时间
【发布时间】: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; 作为源。

标签: c# linq .net-core


【解决方案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,但这根本不在数据库中......还有其他想法......?
  • 没想到会编译,我只是在stackoverflow编辑器上复制编辑了;-)
  • @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,有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-30
  • 1970-01-01
  • 2016-04-22
相关资源
最近更新 更多