2012-12-14 55 views
2

我正在用一些Linq查詢優化一個方法。到目前爲止,執行時間約爲3秒,我試圖減少它。該方法中有相當多的操作和計算,但沒有太複雜的。提高linq查詢的性能

我歡迎任何suggections和思想的表現如何改進和優化代碼。


方法的整個代碼(下面我會指出,我有最大的延遲):

public ActionResult DataRead([DataSourceRequest] DataSourceRequest request) 
{ 
    CTX.Configuration.AutoDetectChangesEnabled = false; 

    var repoKomfortaktion = new KomfortaktionRepository(); 
    var komfortaktionen = CTX.Komfortaktionen.ToList(); 

    var result = new List<AqGeplantViewModel>(); 

    var gruppen = new HashSet<Guid?>(komfortaktionen.Select(c => c.KomfortaktionsGruppeId).ToList()); 

    var hochgeladeneKomplettabzuege = CTX.Komplettabzug.Where(c => gruppen.Contains(c.KomfortaktionsGruppeId)).GroupBy(c => new { c.BetriebId, c.KomfortaktionsGruppeId }).Select(x => new { data = x.Key }).ToList(); 
    var teilnehmendeBetriebe = repoKomfortaktion.GetTeilnehmendeBetriebe(CTX, gruppen); 
    var hochgeladeneSperrlistenPlz = CTX.SperrlistePlz.Where(c => gruppen.Contains(c.KomfortaktionsGruppeId) && c.AktionsKuerzel != null) 
                     .GroupBy(c => new { c.AktionsKuerzel, c.BetriebId, c.KomfortaktionsGruppeId }).Select(x => new { data = x.Key }).ToList(); 

    var hochgeladeneSperrlistenKdnr = CTX.SperrlisteKdnr.Where(c => gruppen.Contains(c.KomfortaktionsGruppeId) && c.AktionsKuerzel != null) 
                     .GroupBy(c => new { c.AktionsKuerzel, c.BetriebId, c.KomfortaktionsGruppeId }).Select(x => new { data = x.Key }).ToList(); 

    var konfigsProAktion = CTX.Order.GroupBy(c => new { c.Vfnr, c.AktionsId }).Select(c => new { count = c.Count(), c.Key.AktionsId, data = c.Key }).ToList(); 
    foreach (var komfortaktion in komfortaktionen) 
    { 
     var item = new AqGeplantViewModel(); 

     var zentraleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 1)).ToList(); 
     var lokaleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 2)).ToList(); 

     var hochgeladeneSperrlistenGesamt = 
       hochgeladeneSperrlistenPlz.Count(c => c.data.AktionsKuerzel == komfortaktion.Kuerzel && c.data.KomfortaktionsGruppeId == komfortaktion.KomfortaktionsGruppeId) + 
       hochgeladeneSperrlistenKdnr.Count(c => c.data.AktionsKuerzel == komfortaktion.Kuerzel && c.data.KomfortaktionsGruppeId == komfortaktion.KomfortaktionsGruppeId); 

     item.KomfortaktionId = komfortaktion.KomfortaktionId; 
     item.KomfortaktionName = komfortaktion.Aktionsname; 
     item.Start = komfortaktion.KomfortaktionsGruppe.StartAdressQualifizierung.HasValue ? komfortaktion.KomfortaktionsGruppe.StartAdressQualifizierung.Value.ToString("dd.MM.yyyy") : string.Empty; 
     item.LokalAngemeldet = lokaleTeilnehmer.Count(); 
     item.ZentralAngemeldet = zentraleTeilnehmer.Count(); 

     var anzHochgelandenerKomplettabzuege = hochgeladeneKomplettabzuege.Count(c => zentraleTeilnehmer.Count(x => x.BetriebId == c.data.BetriebId) == 1) + 
               hochgeladeneKomplettabzuege.Count(c => lokaleTeilnehmer.Count(x => x.BetriebId == c.data.BetriebId) == 1); 

     item.KomplettabzugOffen = (zentraleTeilnehmer.Count() + lokaleTeilnehmer.Count()) - anzHochgelandenerKomplettabzuege; 

     item.SperrlisteOffen = (zentraleTeilnehmer.Count() + lokaleTeilnehmer.Count()) - hochgeladeneSperrlistenGesamt; 

     item.KonfigurationOffen = zentraleTeilnehmer.Count() - konfigsProAktion.Count(c => c.AktionsId == komfortaktion.KomfortaktionId && zentraleTeilnehmer.Any(x => x.Betrieb.Vfnr == c.data.Vfnr)); 

     item.KomfortaktionsGruppeId = komfortaktion.KomfortaktionsGruppeId; 
     result.Add(item); 
    } 

    return Json(result.ToDataSourceResult(request)); 
} 

上半年(之前的foreach)採用半秒這是好的。最大的延遲是在第一次迭代中的foreach語句中,特別是在這些行中,zentraleTeilnehmer的執行首次需要1.5秒。

var zentraleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 1)).ToList(); 
var lokaleTeilnehmer = teilnehmendeBetriebe.Where(c => c.TeilnahmeStatus.Any(x => x.KomfortaktionId == komfortaktion.Id && x.AktionsTypeId == 2)).ToList(); 

TeilnehmendeBetriebe有800行,其中TeilnahmeStatus屬性具有通常約4個項目。所以,最大800 * 4次迭代,這是不畢竟一個巨大的數字...

因此,我主要是在優化這些線,希望執行時間縮短到半秒左右interected。

我試了一下:

  1. 重寫LINQ到的foreach:沒有幫助,同時...也許並不奇怪,但值得一試。

    foreach (var tb in teilnehmendeBetriebe) //836 items 
    { 
        foreach (var ts in tb.TeilnahmeStatus) //3377 items 
        { 
         if (ts.KomfortaktionId == komfortaktion.Id && ts.AktionsTypeId == 1) 
         { 
          testResult.Add(tb); 
          break; 
         } 
        } 
    } 
    
  2. 選擇特定列teilnehmendeBetriebe用。選擇()。也沒有幫助。

無論是幫助其他小的操作我試過了。

有趣的 - 而的foreach的第一次迭代可能需要長達2秒,第二和進一步採取只是milisecons,所以達網絡能夠優化或重新使用的計算數據。

什麼可以改變,以提高性能非常歡迎任何建議!

編輯:

public List<TeilnahmeBetriebKomfortaktion> GetTeilnehmendeBetriebe(Connection ctx, HashSet<Guid?> gruppen) 
    { 
     return ctx.TeilnahmeBetriebKomfortaktion.Include(
             c => c.TeilnahmeStatus).ToList(); 
    } 

EDIT2:
TeilnahmeBetriebKomfortaktion.TeilnahmeStatus在方法GetTeilnehmendeBetriebe急切裝載 正在執行GetTeilnehmendeBetriebe時發送的查詢:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[BetriebId] AS [BetriebId], 
    [Extent1].[MandantenId] AS [MandantenId], 
    [Extent1].[CreatedUser] AS [CreatedUser], 
    [Extent1].[UpdatedUser] AS [UpdatedUser], 
    [Extent1].[CreatedDate] AS [CreatedDate], 
    [Extent1].[UpdatedDate] AS [UpdatedDate], 
    [Extent1].[IsDeleted] AS [IsDeleted] 
    FROM [Semas].[TeilnahmeBetriebKomfortaktion] AS [Extent1] 
    WHERE [Extent1].[IsDeleted] <> cast(1 as bit) 
+0

我們在此討論LINQ to Entities嗎?'repoKomfortaktion.GetTeilnehmendeBetriebe'返回什麼類型? –

+0

@Daniel是的,Linq to Entities。它返回List 。 – Anelook

+0

如果您向我們展示'CTX.Komfortaktionen'查詢,它可能會有所幫助。 –

回答

2

我的假設是,TeilnahmeBetriebKomfortaktion.TeilnahmeStatus是一個懶加載收集,導致N + 1 problem。您應該熱切地獲取該集合以改善您的性能。

foreach循環的以下迭代的速度快,因爲在第一次迭代後的對象不再從數據庫服務器請求,但都從內存的服務器。

+0

想法真的很好!但是,不幸的是,它已經很容易被加載了......(我將這些細節添加到問題描述的末尾) – Anelook

+0

@Anelook:Hm ...你能檢查實際發送到服務器的查詢嗎? –

+0

我檢查了發送的查詢。事實確實如此,我看不到TeilnahmeStatus連接的位置。我將查詢添加到問題描述中。 我相信這個問題確實是以TeilnahmeStatus的方式被檢索到的。 – Anelook