2012-09-03 29 views
3

我從來沒有聽說過它,但人們將應用程序中的問題稱爲「N + 1問題」。他們正在做一個Linq to SQL的項目,並且有人發現了一個性能問題。我不太明白 - 但希望有人能引導我。人們問我要修復N + 1錯誤嗎?

看來,他們正試圖獲得obects的列表,然後在Foreach後引起太多的數據庫訪問:

據我瞭解,源的第二部分只被裝載在forwach。

因此,項目的列表加載:

var program = programRepository.SingleOrDefault(r => r.ProgramDetailId == programDetailId); 

再後來,我們利用這個名單的:

foreach (var phase in program.Program_Phases) 
{ 
    phase.Program_Stages.AddRange(stages.Where(s => s.PhaseId == phase.PhaseId)); 
    phase.Program_Stages.ForEach(s => 
    { 
     s.Program_Modules.AddRange(modules.Where(m => m.StageId == s.StageId)); 
    }); 
    phase.Program_Modules.AddRange(modules.Where(m => m.PhaseId == phase.PhaseId)); 
} 

看來idetified的問題是,他們預計「計劃」到包含它的孩子。但是,當我們提到查詢的孩子,它重新加載proram:

program.Program_Phases 

他們期待節目是滿載並在內存中,並profilder似乎表明,節目表,所有的連接是被稱爲每個'foreach'。

這是否有意義?

(編輯:我foind此鏈接: Does linq to sql automatically lazy load associated entities? 這可能會回答我的quetion,但..他們使用更好的(如人......)符號,而不是這種奇怪的(X => X ....)。因此,如果這個鏈接是答案 - 即我們需要在查詢中「加入」 - 可以這樣做嗎?)

+2

參見:http://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem –

回答

2

對於高性能的linq首先計算出你真正關心的屬性。 linq具有性能優勢的一個優點是你可以輕鬆地省去你不會用到的數據的檢索(你總是可以手工編寫比linq更好的東西,但是linq可以很容易地做到這一點,而不需要創建一個圖書館充滿了數百個課程,每次你忽略了一些細節)。

你說「list」幾次。如果您不需要,不要去獲取列表,只要您不止一次重複使用同一個列表。否則,一次只能處理一件物品的時間將會佔用99%的時間。

你所說的「好」和「奇怪」的語法是說不同的方式來說同樣的事情。有些東西只能用方法和lambda表達,但其他形式總是可以這樣表達 - 實際上是在編譯之後。無論如何,from b in someSource where b.id == 21 select b.name之類的東西編譯爲someSource.Where(b => b.id == 21).Select(b => b.name)

您可以設置DataContext.LoadOptions準確定義哪些實體您想要加載與對象(以及最重要的是,在不同的不同用途很容易設置)。這可以解決你的N + 1問題。

另外,你可能會發現它easer更新現有實體或插入新的,通過自己設置相應的標識。

即使你不覺得它更容易,它可以在某些情況下,速度更快。通常情況下,我會說隨着更容易,忘記性能,只要這個選擇,但如果表現是一個問題在這裏(你說是這樣),那麼可以分析看看哪兩個作品更好,值得。

4

在ORM術語中,通常會出現'N + 1選擇問題'當你有一個嵌套集合屬性的實體時。它指的是使用延遲加載時將實體數據完全加載到內存中所需的查詢數。一般來說,查詢次數越多,客戶端到服務器的往返次數越多,服務器處理查詢所做的工作越多,這可能會對性能產生巨大影響。

有各種技術可以避免這個問題。我不熟悉Linq to SQL,但NHibernate支持在某些情況下提供有用的提取。如果你不需要加載整個實體實例,那麼你也可以考慮做一個投影查詢。另一種可能性是改變實體模型以避免嵌套集合。