2015-06-14 20 views
1

我有一個大集合,我需要根據兩個屬性獲取最新項目。 第一步是根據日期道具排序列表。這很好,很快。重構GroupBy避免放緩對大數據集的操作

然後,我通過兩個屬性對新列表進行分組,並從每個屬性中獲取第一個項目。

var one = Fisks.Where(s=>s.Havn.Id == 1).OrderByDescending(s=>s.Date); 
var two = one.GroupBy(s=>new {s.Arter.Name, s.Sort}); 
var three = two.Select(s=>s.FirstOrDefault()); 

這工作,但它使用的大集合,當它實在是太慢了。我怎樣才能避免使用groupBy,但仍得到相同的結果?

謝謝!

+0

嘗試向數據庫中的表添加索引以提高這些操作的性能。 – dotctor

+0

我認爲你將不可接受的性能歸因於查詢的隨機元素(GroupBy)。使用Profiler和Showplan XML事件捕獲執行計劃。 – usr

+0

我假設你明白這些延期的執行?你確定它是'GroupBy',速度很慢嗎? –

回答

0

使用LINQ僅爲第一步,然後取第一批在一個循環中可以提供對過程更多的控制,避免了分組乾脆:

var query = Fisks 
    .Where(f => f.Havn.Id == 1) 
    .OrderByDescending(f => f.Date) 
    .ThenBy(f => f.Arter.Name) 
    .ThenBy(f => f.Sort); 
var list = new List<Fisk>(); 
foreach (Fisk fisk in query) { 
    if (list.Count == 0) { 
     list.Add(fisk); 
    } else { 
     Fisk last = list[list.Count - 1]; 
     if (fisk.Sort != last.Sort || fisk.Arter.Name != last.Arter.Name) { 
      list.Add(fisk); 
     } 
    } 
} 
0

一般來說,我做某件事之前建議對排序是可能破陣該順序(例如GroupBy可以在LINQ2SQL中生成SQL)。也可以嘗試只訂購你將要使用的東西。如果僅限選擇的必填字段/屬性,則可以提高查詢性能。你可以擺弄這個sample和使用真正後端來代替:

var Fisks=new[]{ 
    new {Havn=new{Id=1},Date=DateTime.MinValue,Arter=new{Name="A"},Sort=1,Title="A1"}, 
    new {Havn=new{Id=1},Date=DateTime.MinValue.AddDays(1),Arter=new{Name="A"},Sort=1,Title="A2"}, 
    new {Havn=new{Id=1},Date=DateTime.MinValue,Arter=new{Name="B"},Sort=1,Title="B1",}, 
    new {Havn=new{Id=1},Date=DateTime.MinValue.AddDays(2),Arter=new{Name="B"},Sort=1,Title="B2",}, 
    new {Havn=new{Id=1},Date=DateTime.MinValue.AddDays(2),Arter=new{Name="B"},Sort=1,Title="B3",}, 
}; 
var stopwatch=Stopwatch.StartNew(); 
var one = Fisks.Where(s=>s.Havn.Id == 1).OrderByDescending(s=>s.Date); 
var two = one.GroupBy(s=>new {s.Arter.Name, s.Sort}); 
var three = two.Select(s=>s.FirstOrDefault()); 
var answer=three.ToArray(); 
stopwatch.Stop(); 
stopwatch.ElapsedTicks.Dump("elapsed Ticks"); 
answer.Dump(); 

stopwatch.Restart(); 
answer=Fisks 
.Where(f=>f.Havn.Id.Equals(1)) 
.GroupBy(s=>new {s.Arter.Name, s.Sort},(k,g)=>new{ 
    s=g.OrderByDescending(s=>s.Date).First()//TOP 1 -> quite fast 
}) 
.Select(g=>g.s) 
.OrderByDescending(s=>s.Date) // only fully order results 
.ToArray(); 
stopwatch.Stop(); 
stopwatch.ElapsedTicks.Dump("elapsed Ticks"); 
answer.Dump(); 

如果你對任何SQL Server的工作,你應該檢查在LINQPad生成的SQL。你不想以n+1 Query結束。索引Havn.IdFisks.Date也可能有所幫助。

+0

有沒有一種很酷的方式來檢查linqpad中查詢的運行時間? 不是時間,而是大O. –

+0

使用您提供的最後一次查詢所花費的時間比我所用的時間慢5秒,所以它看起來沒有區別:) –

+0

您應該真的真的檢查生成的SQL並調整查詢。您也可以複製SQL並使用SSMS查詢分析器。 – mbx