2015-08-06 2 views
0

У меня есть запрос Linq, который занимает гораздо больше времени, чем его эквивалент SQL (около 5-6 секунд для Linq, 50 мс для SQL). Очевидно, что что-то не так в переводе, у меня даже есть идея, но я не знаю, как ее решить. Запрос ниже:Ошибка производительности с помощью запроса Linq - свойства навигации в вине?

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), 
}; 

Я подозреваю, что использование навигационной собственности пользователя в моей группе вызывает подзапрос будет выполняться для каждой записи в 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), 
}; 

Но мой выбор все еще выглядит идентично, возможно, свойство навигации Есть вызывает подобные проблемы? Это кажется странным, хотя, поскольку я использовал свойства navigatio в выборе запросов Linq, прежде чем без проблем. В любом случае, я не уверен, что мои подозрения верны, и если да, то почему это происходит и как я могу это исправить.

+0

Нет необходимости в 'g.FirstOrDefault()', потому что выбор будет выполняться только при наличии коллекции, возвращаемой 'groupby'. –

ответ

0

Я подозреваю, что выражения, чтобы получить CompanyID, CompanyName и Дата являются слишком сложными и Linq To Sql не может перевести это в надлежащем Sql.

1) попытаться удалить часть, которая выбирает CompanyID, НазваниеКомпании и Дата, чтобы увидеть, если он становится быстрее;

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.CompanyId, g.Key.CompanyName и g.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), если это поможет, добавить нулевой чек обратно, и вы должны получить тот же результат, но Быстрее;

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), 
    }; 
+0

Спасибо за советы. Удаление CompanyId и CompanyName действительно значительно улучшило производительность (натолкнуло ее примерно на 250 мс, что хорошо). Однако замена вызова FirstOrDefault() ключом не изменила производительность (еще около 4 секунд), а также нулевую проверку. – urrmurrmur

+0

Не могли бы вы отправить SQL-запрос, который создается LINQ? Вы можете использовать SQL Server Profiler для извлечения запроса. –

+0

Кроме того, попробуйте выполнить запрос без сглаживания ключа GroupBy. ... группировать данные по новым {user.CompanyId, company.Name, data.Date} в г выбрать новый GroupedDayData { Id = g.Key.CompanyId, Name = g.Key.Name, Date = g.Key.Date, Шаги = g.Sum (x => x.Steps), ... –