2011-02-28 7 views
1

면책 조항 : 나는 Linq에 약간의 경험이 있습니다.Linq와 루프를 최적화하는 데 도움이 필요

내 작업에서 내 작업 중 하나는 전자 상거래 웹 사이트를 유지하는 것입니다. 어제 Google 고객 중 한 명이 Google 용 피드 파일을 만들려고 할 때 발생하는 시간 초과에 대해 불평하기 시작했습니다. 사용자가 9,000 개가 넘는 항목을 피드 파일에 넣을 경우 Google 코드에서 실행하는 데 최소 1 분이 소요됩니다.

디버거를 실행하여 문제의 원인을 찾을 수 없으므로 프로필러 (ANTS)를 실행하여 문제를 해결하도록했습니다. 그것은 우리의 문제의 근원, linq 코드의 비트를 포함 foreach 루프를 발견했다. 코드는 다음과 같습니다.

var productMappings = GoogleProductMappingAccess.GetGoogleProductMappingsByID(context, productID); 
List<google_Category> retCats = new List<google_Category>(numCategories); 
int added = 0; 

//this line was flagged by the profiler as taking 48.5% of total run time 
foreach (google_ProductMapping pm in (from pm in productMappings orderby pm.MappingType descending select pm)) 
{ 
    if (pm.GoogleCategoryId.HasValue && pm.GoogleCategoryId > 0) 
    { 
     //this line was flagged as 36% of the total time 
     retCats.Add(pm.google_Category); 
    } 

    else if (pm.GoogleCategoryMappingId.HasValue && pm.GoogleCategoryMappingId > 0) 
    { 
     retCats.Add(pm.google_CategoryMapping.google_Category); 
    } 
    else 
    { 
     continue; 
    } 

    if (++added >= numCategories) 
    { 
     break; 
    } 
} 

경험이 많은 개발자 중 아이디어가 있습니까? 나는 linq 모든 SQL을 대체하려고 노력하고 놀고 있었지만, 그것이 최선의 과정은 여기에 있는지 확실하지 오전 (linq로 작성된 경우, 그것에 대한 이유가 있어야합니다).

+0

루프에서 linq을 수행하지 마십시오. 결과를 변수에 저장하고 사용하십시오. – madmik3

+0

빠른 수정을 위해 DataContext.CommandTimeout을 위로 올리십시오. –

+0

그렇게 할 필요가 없어 질 수도 있습니다. 가능하다면 피하기를 좋아한다. – CountMurphy

답변

2

당신이 orderby을 사용하는 모두가 평가 될 필요가 있기 때문에, 따라서 이러한 모든 결과는 쿼리에서 처리를 사용

productMappings.Where(pm => (pm.GoogleCategoryMappingId.HasValue 
           && pm.GoogleCategoryMappingId > 0) 
           ||(pm.GoogleCategoryMappingId.HasValue && 
           pm.GoogleCategoryMappingId > 0) 
        ) 
       .OrderBy(...) 

또한 최대 numCategories까지만 사용하므로 쿼리에서 반환하는 결과의 수를 제한해야합니다. foreach 루프 내에서 확인하는 대신

.Take(numCategories) 

을 쿼리에 추가하십시오.

+0

나는 이것을 시험해보고, 어떤 일이 일어 났는지 알려 줄 것이다. – CountMurphy

+0

추가 된 where 절은 48 %에서 78 %로 시간을 단축했다. 테이크는별로 할 여지가 없었습니다. – CountMurphy

+0

테이블이 얼마나 큽니까? 'MappingType' (그리고 그 문제에 대한 where 절의 다른 컬럼들)에 적절한 인덱스가 있습니까? – BrokenGlass

0

데이터베이스 스키마를 알지 못하면 실제로 알기가 어렵습니다. 몇 가지 아이디어 :

1) 데이터베이스 엔진 튜닝 관리자를 통해 쿼리를 실행합니다. 쿼리에 인덱스가 필요할 수도 있습니다.

2)이 정보를 사전 처리하여 다른 테이블 또는 파일에 넣습니다. 그렇게하면 Google에서 시간 제한을 요청하지 않습니다. - 당신은 당신이 어쨌든 쿼리가 더 빠르게 처리 될 수 원하지 않는 결과를 필터링 할 수 있습니다 경우

1

이유는 retCats.Add(pm.google_Category);이 오래 걸리는 이유는 서버로 돌아가는 느리게로드되는 객체를 참조하기 때문입니다. 리팩터링을 통해 전체 객체 대신 ID의 로컬 복사본 만 가져 오면 해당 부분의 속도가 빨라집니다.

전체 개체를 가져와야하는 경우 productMappings을 가져올 때 단일 쿼리에서 개체를 가져올 수있는 방법을 조사하십시오. 이렇게하는 방법은 SQL에서 사용하는 LINQ 래퍼에 따라 다릅니다.

+0

일단 처음으로 목이 고정되면 더 자세히 살펴볼 것입니다. 감사합니다. – CountMurphy

0

이것은 아마 작동합니다 : GetGoogleProductMappingsByID는 IQueryable (해당되는 경우)을 반환하는 경우

var productMappings = GoogleProductMappingAccess.GetGoogleProductMappingsByID(context, productID); 
var categories = from pm in productMappings 
       where pm.GoogleCategoryId > 0 || 
         pm.GoogleCategoryMappingId > 0 
       orderby pm.MappingType descending 
       select pm.google_Category ?? 
         pm.google_CategoryMapping.google_Category; 

return categories.Take(numCategories); 

그것은 가장 잘 작동합니다. 그렇다면 LINQ는 전체 문을 T-SQL 명령으로 변환하므로 메모리 LINQ보다 훨씬 빠릅니다.

마지막 문장에 .ToList()를 추가하여 코드에서와 동일한 반환 유형으로 가져오고 (LINQ 문의 강제 실행) 자유롭게 사용해보십시오.

.HasValue와> 0을 모두 확인하는 것은 쓸모가 없습니다. Id> 0인지 확인하는 것으로 충분합니다.
자세한 정보 : http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx (연산자)

+0

지금 당장 이걸 드리겠습니다. .hasvalue에 동의했다. 테이블의 모든 내용이 1 또는 0 – CountMurphy

+0

컴파일 오류입니다. 쿼리 본문은 select 절 또는 group 절로 끝나야합니다. 이상한 것은 내가 select 절을 보았 기 때문에 컴파일러가 무엇을 만들고 있는지 알지 못한다. – CountMurphy

+0

아, 내 생각에 그것은 '내림차순'대신 'desc'를 입력하는 실수였다. 미안 해요 Visual Studio없이 입력하므로 구문 유효성 검사 :) – Zyphrax

관련 문제