2014-12-10 4 views
0

Использование 4.5.1 с приложением, которое на стороне сервера перемещает данные диаграммы со многими запросами REST одновременно.Недостаточно памяти Комбинация лямбда против встроенных делегатов

Используйте IQueryable для создания запросов. Например, я первоначально был следующим:

var query = ctx.Respondents 
    .Join(
    ctx.Respondents, 
    other => other.RespondentId, 
    res => res.RespondentId, 
    (other, res) => new ChartJoin { Respondent = res, Occasion = null, BrandVisited = null, BrandInfo = null, Party = null, Item = null } 
    ) 
    . // bunch of other joins filling out the ChartJoin 
    .Where(x => x.Respondent.status == 1) 
    . // more Where clauses dynamically applied 
    .GroupBy(x => new CommonGroupBy { Year = (int)x.Respondent.currentVisitYear, Month = (int)x.Respondent.currentVisitMonth }) 
    .OrderBy(x => x.Key.Year) 
    .ThenBy(x => x.Key.Month) 
    .Select(x => new AverageEaterCheque 
    { 
     Year = x.Key.Year, 
     Month = x.Key.Month, 
     AverageCheque = (double)(x.Sum(m => m.BrandVisited.DOLLAR_TOTAL)/x.Sum(m => m.BrandVisited.NUM_PAID)), 
     Base = x.Count(), 
     Days = x.Select(m => m.Respondent.visitDate).Distinct().Count() 
    }); 

Для обеспечения динамической группировки (через клиент), то GroupBy был сгенерирован с C# выражений, возвращающих словарь. Выбор также должен был быть сгенерирован с помощью выражений. Вышеуказанный Select стал чем-то вроде:

public static Expression<Func<IGrouping<IDictionary<string, object>, ChartJoin>, AverageEaterCheque>> GetAverageEaterChequeSelector() 
{ 
    // x => 
    var ParameterType = typeof(IGrouping<IDictionary<string, object>, ChartJoin>); 
    var parameter = Expression.Parameter(ParameterType); 

    // x => x.Sum(m => m.BrandVisited.DOLLAR_TOTAL)/x.Sum(m => m.BrandVisited.NUM_PAID) 
    var m = Expression.Parameter(typeof(ChartJoin), "m"); 

    var mBrandVisited = Expression.PropertyOrField(m, "BrandVisited"); 

    PropertyInfo DollarTotalPropertyInfo = typeof(BrandVisited).GetProperty("DOLLAR_TOTAL"); 
    PropertyInfo NumPaidPropertyInfo = typeof(BrandVisited).GetProperty("NUM_PAID"); 

    .... 

    return a lambda... 
} 

Когда я провел тестовый прогон локально, у меня возникла ошибка «Из памяти». Затем я начал читать блоги от Totin и других, которые компилируются Lambda, деревья выражений вообще дороги. Не думал, что это ударит по моему приложению. И мне нужна возможность динамически добавлять группировки, которые приводят меня к использованию деревьев выражений для предложений GroupBy и Select.

Хотели бы некоторые указания о том, как преследовать нарушителей памяти в моем приложении? Видели, что некоторые люди используют dotMemory, но были бы здоровы и с некоторыми практическими советами. Очень мало опыта в мониторинге C#, DotNet.

+1

Я бы сначала проверил данные, возвращаемые вашим EF-запросом. Скорее всего, это память, чем выражение. – user1620220

+0

Код, который вы указали, не использует выражение, которое вы создаете вообще. Как мы можем рассказать вам, что вы делаете неправильно с кодом, который вы нам не показали? – Servy

+0

@Servy, вопрос показывает жестко закодированные предложения GroupBy и Select, написанные как встроенные lambda, а затем краткий пример написания предложения Select с помощью выражений. Это переключение, когда я заметил проблемы с памятью. –

ответ

4

Поскольку вы компилируете выражение в делегат, операция выполняется с использованием LINQ to Objects, а не с использованием перегрузки IQueryable. Это означает, что весь набор данных извлекается в память и вся обработка, выполняемая приложением, вместо обработки, выполняемой в базе данных, и только конечные результаты, отправляемые в приложение.

По-видимому, вытащить всю таблицу в память достаточно, чтобы запустить приложение из памяти.

Вам необходимо не скомпилировать лямбду и оставить ее в качестве выражения, что позволяет поставщику запроса перевести его в SQL, как это делается с исходным кодом.

+0

в строке 20 в моем Gist Я могу удалить вызов компиляции в предложении GroupBy. Однако я не могу удалить его из предложения Select в строке 28. Вот почему Compile завалена повсюду. Есть ли проблема с моей сигнатурой метода? –

+0

@MatthewYoung Очень важно, чтобы вы не компилировали ни одно из выражений. Компилируя их в делегаты, вы принудительно вводите код в LINQ-to-Objects. Вам нужно использовать EF и быть переведены в SQL-код. Этого не может произойти, если вы скомпилируете выражения. – Servy

+0

Я худею, вы на корневую проблему. Появилась ошибка при удалении Compile() из группы By, поскольку LINQ to Entities не распознает мой объект словаря, и метод не может быть переведен в выражение хранилища. –

Смежные вопросы