2012-09-11 8 views
3


나는 목록에 약 200,000 개의 레코드가 있으며 그 중 하나를 반복하여 다른 컬렉션을 만들고 있습니다. 내 로컬 64 비트 승리 7 잘 작동하지만 Windows Server 2008 R2 이동할 때 많은 시간이 걸립니다. 거의 1 시간 정도의 차이가 있습니다!개체에 대한 LINQ 최적화 쿼리

나는 컴파일 된 쿼리를 조사해 보았고 여전히 그것을 파악하고있다. 여러 가지 이유로
, 우리는 데이터베이스가 가입하고 아이가 여기

값 검색을 수행하지 못할 것은 코드 :

//listOfDetails is another collection 
List<SomeDetails> myDetails = null; 
foreach (CustomerDetails myItem in customerDetails) 
{ 

    var myList = from ss in listOfDetails 
       where ss.CustomerNumber == myItem.CustomerNum 
       && ss.ID == myItem.ID 
       select ss; 
    myDetails = (List<SomeDetails>)(myList.ToList()); 
    myItem.SomeDetails = myDetails; 
} 
+0

수정 해 주셔서 감사합니다. – hangar18

+1

두 서버의 항목이 같습니까? 비교할만한 하드웨어? 로컬 Win7에 얼마나 걸리나요 (시간은 800 % 또는 1 % 일 수 있습니다). – driis

+0

예 .. 기록의 수는 동일합니다. Windows 7에서는이 루프를 처리하는 데 약 2 분이 걸리지 만 서버에서는 약 70 분이 소요됩니다! – hangar18

답변

3

성능의 차이를 왜 나도 몰라,하지만 당신은해야한다 코드를 더 잘 수행 할 수 있습니다.

//listOfDetails is another collection 
List<SomeDetails> myDetails = ...; 
detailsGrouped = myDetails.ToLookup(x => new { x.CustomerNumber, x.ID }); 
foreach (CustomerDetails myItem in customerDetails) 
{ 
    var myList = detailsGrouped[new { CustomerNumber = myItem.CustomerNum, myItem.ID }]; 
    myItem.SomeDetails = myList.ToList(); 
} 

여기 아이디어는 myDetails에 반복 반복하지 않도록하고, 대신 해시를 기반으로 조회를 구축하는 것입니다. 일단 그것이 빌드되면 조회를 수행하는 것이 매우 저렴합니다.

+0

고마워요. 나는 이것을 시도하고 당신에게 알려줄 것입니다. – hangar18

6

나는 다르게 이런 짓을 했을까 :

var lookup = listOfDetails.ToLookup(x => new { x.CustomerNumber, x.ID }); 
foreach(var item in customerDetails) 
{ 
    var key = new { CustomerNumber = item.CustomerNum, item.ID }; 
    item.SomeDetails = lookup[key].ToList(); 
} 

이 코드의 가장 큰 장점은 단지 한 번 listOfDetails을 반복 조회 구축한다는 것이다 - 해시 맵에 불과하다. 그 다음에는 키를 사용하여 값을 얻습니다.이 값은 해시 맵이 만들어지는 것과 같이 매우 빠릅니다.

+1

성능이 향상되었습니다. 실행 시간이 27 초에서 20 초로 줄었습니다.:) –

1

내부 ToList()는 각 루프에 대한 평가를 강요합니다. SelectMany는이 같은 ToList, 뭔가를 방지 할 수 있습니다 당신이 먼저 모든 SomeDetails를 가져온 다음 항목에 할당하는 경우는 속도를 수

var details = customerDetails.Select(item => listOfDetails 
    .Where(detail => detail.CustomerNumber == item.CustomerNum) 
    .Where(detail => detail.ID == item.ID) 
    .SelectMany(i => i as SomeDetails) 
); 

. 그렇지 않을 수도 있습니다. 시간을 어디에서 가져 가는지 실제로 파악해야합니다.

+2

O (n) 대신 O (N^2)가 여전히 있습니다. –

+0

네,하지만 반드시 모든 작업을 수행 할 필요는 없습니다. 내 요점은 우리가 게으른 평가의 잠재적 이점을 잃을 때마다 ToList()를 수행하는 것입니다. – Aidan

1

그래서, 당신은 아마 여기에 가입 혜택을 거라고 생각 :

var mods = customerDetails 
    .Join(
     listOfDetails, 
     x => Tuple.Create(x.ID, x.CustomerNum), 
     x => Tuple.Create(x.ID, x.CustomerNumber), 
     (a, b) => new {custDet = a, listDet = b}) 
    .GroupBy(x => x.custDet) 
    .Select(g => new{custDet = g.Key,items = g.Select(x => x.listDet).ToList()}); 

foreach(var mod in mods) 
{ 
    mod.custDet.SomeDetails = mod.items; 
} 

나는이 코드를 컴파일하지 않았다 ...

하나에서 항목의 일치에 가입과 함께 다른 목록에 대한 목록은 O (n) 시간에 두 번째 목록의 해시 테이블과 같은 모음 (Lookup)을 작성하여 수행됩니다. 그런 다음 첫 번째 목록을 반복하고 Lookup에서 항목을 가져 오는 문제입니다. 해시 테이블에서 데이터를 가져 오는 것이 O (1)이기 때문에 후속 GroupBy와 마찬가지로 반복/일치 단계에서도 O (n) 만 사용합니다. 따라서 모든 연산에서 O (n)과 동등한 ~ O (3n)을 취해야합니다. 여기서 n은 긴 목록의 길이입니다.