2014-12-10 1 views
0

4.5.1을 서버 측에서 동시에 많은 REST 요청이있는 차트 데이터를 섞는 응용 프로그램과 함께 사용합니다.메모리 부족 Lambda 컴파일 대 인라인 대리자

쿼리를 작성하려면 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#을 식으로 생성 된 예를 들어, I 원래은 다음했다. 또한 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과 그 외의 블로그를 읽기 시작했습니다. 일반적으로 표현식 트리는 비쌉니다. 내 응용 프로그램을 날려 버릴 생각은 없었어. GroupBy 및 Select 절에 Expression Tree를 사용하도록 그룹화를 동적으로 추가하는 기능이 필요합니다.

내 애플리케이션에서 메모리 위반자를 추적하는 방법에 대한 몇 가지 정보가 있습니까? 일부 사람들이 dotMemory를 사용하는 것을 보았지만 실용적인 팁이 있으면 좋을 것입니다. C#, DotNet 모니터링에 대한 경험이 거의 없습니다.

+1

먼저 EF 쿼리에서 반환하는 데이터를 확인합니다. 그것은 표현보다 메모리를 많이 쓰는 경향이 있습니다. – user1620220

+0

표시 한 코드는 작성중인 표현식을 사용하고 있지 않습니다. 우리에게 보여주지 않은 코드를 어떻게 잘못하고 있는지 말할 수 있습니까? – Servy

+0

@Servy, 질문은 인라인 람다로 작성된 하드 코딩 된 GroupBy 및 Select 절 다음에 식으로 Select 절을 작성하는 간단한 예제를 보여줍니다. 전환은 메모리 문제를 발견했을 때입니다. –

답변

4

표현식을 위임자로 컴파일하므로 오버로드를 사용하는 대신 IQueryable 오버로드를 사용하는 대신 LINQ to Objects를 사용하여 작업을 수행합니다. 즉, 데이터 세트 전체가 메모리로 가져오고 모든 처리가 응용 프로그램에 의해 처리되는 대신 데이터베이스에서 수행되고 최종 결과 만 응용 프로그램에 전송됩니다.

분명히 전체 테이블을 메모리로 가져 와서 응용 프로그램을 메모리 부족으로 실행할 수 있습니다.

이 아니고은 람다를 컴파일하고 표현식으로 남겨 두어 쿼리 공급자가 원본 코드에서와 같이 SQL로 변환 할 수 있도록해야합니다.

+0

내 Gist의 20 행에서 GroupBy 절에서 컴파일 호출을 제거 할 수 있습니다. 그러나 28 행의 Select 절에서이를 제거 할 수 없습니다.이 때문에 Compile이 모든 곳에서 산재 해 있습니다. 내 메소드 서명에 문제가 있습니까? –

+0

@MatthewYoung 표현식을 컴파일하지 않는 것이 중요합니다. 대리자로 컴파일하여 LINQ-to-Objects로 코드를 강제 적용합니다. EF를 사용하고 SQL 코드로 변환해야합니다. 표현식을 컴파일하면 이런 일은 일어나지 않습니다. – Servy

+0

나는 근본 문제를 해결하려고합니다. LINQ to Entities가 내 사전 개체를 인식하지 못하고 그 메서드를 저장소 식으로 변환 할 수 없다는 점에서 Group By에서 Compile()을 제거하면 오류가 발생합니다. –