2011-10-14 44 views
3

我目前有一個系統,用戶可以註冊和下注足球比賽的比分。 現在我有超過20K的用戶,並有超過300萬的投注。每週我必須生成一個排名,所以我必須加載在內存中的所有用戶用下注只是這樣的查詢:從實體框架中的LINQ查詢優化內存使用4.1

from u in context.Set<User>().include("Bets").OrderByDescending(u => u.Points) 
select u 

點在哪裏從每次猜測賺取積分的總和。 查詢結束後,我將用戶和他的位置保存在另一張桌子上,以建立我的排名。

問題是,這個查詢消耗的內存太多了!超過4GB!我需要所有用戶和投注來計算排名。

我嘗試的第一個選擇是:創建另一個表來存儲用戶及其點。我想在此查詢加載迭代,每次500個用戶,不是計算和保存,但我仍然停留在內存的問題:

 int page = 0; 
     int step = 500; 
     while (page * step < count) 
     { 
      foreach (var u in context.Set<User>() 
              .Skip(page * step) 
              .Take(step).ToList()) 
      { 
       //Saves in another table 
      } 
      page++; 
     } 
     //Sorts based on the data from this other table 

因爲這沒有工作,我放棄了,然後我試圖做是這樣的:

var users = (from u in context.Set<User>().Include("Bets") 
      select u).ToList(); 
context.Dispose() 
var sortedUsers = from u in users.OrderByDescending(u => u.Points) 
        select u; 

但沒解決,以及...

我想這個問題是關於上下文保留所有跟蹤信息。 有沒有人有任何線索?如何使用EF 4.1處理大量數據?

感謝


,我注意到另一件事。 比方說,我有用戶A和用戶B, 每個人都有唯一1注相同的比賽,我希望有這樣的事情:

User A ---> Bet 
       \ 
        Match 
       /
User B ---> Bet 

但我有具有相同比賽的兩個不同的實例數據。 有沒有辦法避免這種情況?


爲什麼我不願意把這個在一個存儲過程:

排名是基於猜測,有關於這個排序的一些規則。

用戶有N個賭注。與有比分的比賽相關的每個投注。

第一個排序標準是要點。所以我需要計算每個賭注的分數(每個用戶有大約200個賭注,並且在冠軍結束時將有大約300個賭注)。這是第一次加入。

要計算每個投注的積分,我需要比賽的最終比分。這是另一個加入。

具有每個下注的點的總和(其具有約10條件語句),並通過將其分選後,我仍然需要基於來挑選:

正確投注號,投注其中的 號贏家被猜到了, 其中一個得分被猜測的投注, 最後一個投注日期, 註冊日期。

所以這是一個巨大的排序與約6準則,以及約3聯接和大量的邏輯。在LINQ中計算這個值是非常微不足道的,如果我不得不把它放在SP上,它會花費很多時間,並且更容易出錯。 (沒試過TDD,甚至單元測試的SP ...這個排名對一切測試)

+0

如果您不需要更新這些'User'對象,我可以建議你使用存儲過程來做到這一點的計算。順便說一句,當你執行'.ToList()'時,你實現了你的查詢,並且實際上檢索你的數據庫中的所有數據到你的應用程序內存。 –

+0

使用存儲過程是不現實的,計算比我在這裏發佈的要複雜得多。所以我正在計算內存。 –

回答

1

老兄,我認爲這將是明智,如果你只是計算這些數據在存儲過程中,而不是在你的C#代碼。如果可以通過使用現有數據進行計算,則無需保存這些數據。將它們保存在另一個表中會導致數據冗餘,並且會違反良好數據庫規範化的規則。

+0

我同意你的反規範化。我認爲這是避免使用記憶的一種方式。系統的大部分邏輯就是這些計算。如果我把所有東西都放在SP上,那麼維護起來會很糟糕,所以我現在試圖找到一個更好的選擇。感謝您的幫助 –

+0

嘿,哥們兒今天晚上剛剛閱讀了新的信息。嘗試使用PLINQ,它可以在不同線程中同時執行多個計算:)這可以比常規LINQ計算得更快。 –

+0

我想到了這一點,但我的問題是不是在計算,但是在存儲:DI不認爲有一個PLINQ到實體,現在將搜索... –

3

我@Allan同意,這將理想中的存儲過程來完成。如果您可以發佈計算的詳細信息,也許其他人可以建議在存儲過程中執行此操作的方法。

如果你想保留的東西,因爲他們,有一對夫婦的事情,你可以嘗試:

  1. 使用AsNoTracking以避免緩存:context.Set<User>().AsNoTracking() // etc
  2. 如果您UserBet類有很多您不需要進行計算的屬性,將它們投影到只有您需要的屬性的匿名類型中。

希望這會有所幫助,如果您嘗試AsNoTracking,我會很好奇,知道它有多大的差異。

+0

我會看看這個AsNoTracking,並會讓你知道。看看我對這個問題的更新;) 我在想,如果有計算它和節約表中的結果後釋放從每個用戶的存儲方式... –

+0

的AsNoTracking給予了提振,內存使用情況增長比以前慢,但仍然出現OutOfMemory異常 –