Linq查询的性能问题 - 归咎于导航属性?

时间:2015-08-06 00:22:32

标签: c# performance linq

我的Linq查询花费的时间远远长于SQL等效(Linq约为5-6秒,SQL为50毫秒)。显然翻译中出现了问题,我甚至不知道是什么,但我不知道如何解决它。查询如下:

from data in DbContext.CoacheeData
group data by new { data.User.CompanyId, data.Date } into g
select new GroupedDayData
{
    Id = g.FirstOrDefault().User.CompanyId == null ? "none" : g.FirstOrDefault().User.CompanyId,
    Name = g.FirstOrDefault().User.Company.Name == null ? "none" : g.FirstOrDefault().User.Company.Name,
    Date = g.FirstOrDefault().Date,
    Steps = g.Sum(x => x.Steps),
    Distance = g.Sum(x => x.Distance),
    CaloriesBurned = g.Sum(x => x.CaloriesBurned),
    LightlyActiveMinutes = g.Sum(x => x.LightlyActiveMinutes),
    FairlyActiveMinutes = g.Sum(x => x.FairlyActiveMinutes),
    VeryActiveMinutes = g.Sum(x => x.VeryActiveMinutes),
};

我怀疑在我的group by中使用导航属性User会导致为CoacheeData中的每条记录执行子查询。通过手动加入用户和公司表,我可以将效率提高大约1.5秒,如下所示:

from data in DbContext.CoacheeData
join user in DbContext.Users on data.UserId equals user.Id
join company in DbContext.Companies on user.CompanyId equals company.Id
group data by new { user.CompanyId, company.Name, data.Date } into g
select new GroupedDayData
{
    Id = g.FirstOrDefault().User.CompanyId == null ? "none" : g.FirstOrDefault().User.CompanyId,
    Name = g.FirstOrDefault().User.Company.Name == null ? "none" : g.FirstOrDefault().User.Company.Name,
    Date = g.FirstOrDefault().Date,
    Steps = g.Sum(x => x.Steps),
    Distance = g.Sum(x => x.Distance),
    CaloriesBurned = g.Sum(x => x.CaloriesBurned),
    LightlyActiveMinutes = g.Sum(x => x.LightlyActiveMinutes),
    FairlyActiveMinutes = g.Sum(x => x.FairlyActiveMinutes),
    VeryActiveMinutes = g.Sum(x => x.VeryActiveMinutes),
};

但我的选择看起来仍然相同,也许导航属性导致类似的问题?这看起来很奇怪,因为我之前在选择Linq查询中使用了navigatio属性而没有问题。无论如何,我不确定我的怀疑是否正确,如果是的话,为什么会发生以及如何解决它。

1 个答案:

答案 0 :(得分:0)

我怀疑要获取 CompanyId CompanyName Date 的表达式太复杂,Linq To Sql无法在正确的Sql中翻译它

1)尝试删除选择 CompanyId CompanyName Date 的部分以查看它是否变快;

var result =
    from data in DbContext.CoacheeData
    join user in DbContext.Users on data.UserId equals user.Id
    join company in DbContext.Companies on user.CompanyId equals company.Id
    group data by new { CompanyId = user.CompanyId, CompanyName = company.Name, Date = data.Date } into g
    select new GroupedDayData
    {
        Steps = g.Sum(x => x.Steps),
        Distance = g.Sum(x => x.Distance),
        CaloriesBurned = g.Sum(x => x.CaloriesBurned),
        LightlyActiveMinutes = g.Sum(x => x.LightlyActiveMinutes),
        FairlyActiveMinutes = g.Sum(x => x.FairlyActiveMinutes),
        VeryActiveMinutes = g.Sum(x => x.VeryActiveMinutes),
    };

2)如果有帮助,请用g.Key.CompanyIdg.Key.CompanyNameg.Key.Date

之类的内容替换您的表达方式
var result =
    from data in DbContext.CoacheeData
    join user in DbContext.Users on data.UserId equals user.Id
    join company in DbContext.Companies on user.CompanyId equals company.Id
    group data by new { CompanyId = user.CompanyId, CompanyName = company.Name, Date = data.Date } into g
    select new GroupedDayData
    {
        Id = g.Key.CompanyId,
        Name = g.Key.CompanyName,
        Date = g.Key.Date,
        Steps = g.Sum(x => x.Steps),
        Distance = g.Sum(x => x.Distance),
        CaloriesBurned = g.Sum(x => x.CaloriesBurned),
        LightlyActiveMinutes = g.Sum(x => x.LightlyActiveMinutes),
        FairlyActiveMinutes = g.Sum(x => x.FairlyActiveMinutes),
        VeryActiveMinutes = g.Sum(x => x.VeryActiveMinutes),
    };

3)如果这有帮助,请添加null check,你应该得到相同的结果,但速度更快;

var result =
    from data in DbContext.CoacheeData
    join user in DbContext.Users on data.UserId equals user.Id
    join company in DbContext.Companies on user.CompanyId equals company.Id
    group data by new { CompanyId = user.CompanyId, CompanyName = company.Name, Date = data.Date } into g
    select new GroupedDayData
    {
        Id = g.Key.CompanyId ?? "None",
        Name = g.Key.CompanyName ?? "None",
        Date = g.Key.Date,
        Steps = g.Sum(x => x.Steps),
        Distance = g.Sum(x => x.Distance),
        CaloriesBurned = g.Sum(x => x.CaloriesBurned),
        LightlyActiveMinutes = g.Sum(x => x.LightlyActiveMinutes),
        FairlyActiveMinutes = g.Sum(x => x.FairlyActiveMinutes),
        VeryActiveMinutes = g.Sum(x => x.VeryActiveMinutes),
    };