2012-09-11 48 views
3


我在列表中有20萬左右的記錄,我通過循環和他們形成另一個集合。這在我的本地64位Win 7上正常工作,但是當我將它移到Windows Server 2008 R2時,它需要很長時間。差不多有差不多一個小時!優化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

是的..記錄的數量是相同的。在Win 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,是這樣的:

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

如果你第一次得到所有SomeDetails,然後將它們分配到項目,它可能會加快。或者它可能不會。你應該真的知道時間在哪裏。

+2

這仍然是O(N^2)而不是O(n) –

+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),迭代/匹配階段也只需要O(n),就像後續的GroupBy一樣。所以在所有的操作中都應該採取〜O(3n),這相當於O(n),其中n是較長列表的長度。