2012-04-05 93 views
4

我有這樣的代碼:烏鴉DB DocumentStore - 拋出內存異常

public bool Set(IEnumerable<WhiteForest.Common.Entities.Projections.RequestProjection> requests) 
    { 
     var documentSession = _documentStore.OpenSession(); 
     //{ 
     try 
     { 
      foreach (var request in requests) 
      { 
       documentSession.Store(request); 
      } 
      //requests.AsParallel().ForAll(x => documentSession.Store(x)); 
      documentSession.SaveChanges(); 
      documentSession.Dispose(); 
      return true; 
     } 
     catch (Exception e) 
     { 
      _log.LogDebug("Exception in RavenRequstRepository - Set. Exception is [{0}]", e.ToString()); 
      return false; 
     } 
     //} 
    } 

此代碼被調用多次。當我得到大約50,000個已通過它的文檔後,我得到一個OutOfMemoryException。 任何想法爲什麼?也許過了一段時間,我需要申報一個新的DocumentStore?

謝謝

**

  • UPDATE:

**

我結束了使用批處理/補丁API來執行我所需要的更新。 你可以看到這裏的討論:https://groups.google.com/d/topic/ravendb/3wRT9c8Y-YE/discussion

基本上,因爲我只需要對我的對象更新1個屬性,並考慮有關重新序列化所有對象回JSON ayendes的意見後,我做了這樣的事情:

internal void Patch() 
    { 
     List<string> docIds = new List<string>() { "596548a7-61ef-4465-95bc-b651079f4888", "cbbca8d5-be45-4e0d-91cf-f4129e13e65e" }; 
     using (var session = _documentStore.OpenSession()) 
     { 
      session.Advanced.DatabaseCommands.Batch(GenerateCommands(docIds)); 
     } 
    } 

    private List<ICommandData> GenerateCommands(List<string> docIds) 
    { 
     List<ICommandData> retList = new List<ICommandData>(); 

     foreach (var item in docIds) 
     { 
      retList.Add(new PatchCommandData() 
      { 
       Key = item, 
       Patches = new[] { new Raven.Abstractions.Data.PatchRequest() { 
       Name = "Processed", 
       Type = Raven.Abstractions.Data.PatchCommandType.Set, 
       Value = new RavenJValue(true) 
      }}}); 
     } 

     return retList; 
    } 

希望這有助於...

非常感謝。

回答

4

我剛剛爲我目前的項目做了這個。我將數據分塊,並將每個塊保存在新的會話中。這也可能適用於你。

請注意,此示例一次顯示1024個文檔的分塊,但在決定值得分塊之前至少需要2000個文檔。到目前爲止,我的插入程序以4096的塊大小獲得了最佳性能。我認爲這是因爲我的文檔相對較小。

internal static void WriteObjectList<T>(List<T> objectList) 
{ 
    int numberOfObjectsThatWarrantChunking = 2000; // Don't bother chunking unless we have at least this many objects. 

    if (objectList.Count < numberOfObjectsThatWarrantChunking) 
    { 
     // Just write them all at once. 
     using (IDocumentSession ravenSession = GetRavenSession()) 
     { 
      objectList.ForEach(x => ravenSession.Store(x)); 
      ravenSession.SaveChanges(); 
     } 

     return; 
    } 

    int numberOfDocumentsPerSession = 1024; // Chunk size 

    List<List<T>> objectListInChunks = new List<List<T>>(); 

    for (int i = 0; i < objectList.Count; i += numberOfDocumentsPerSession) 
    { 
     objectListInChunks.Add(objectList.Skip(i).Take(numberOfDocumentsPerSession).ToList()); 
    } 

    Parallel.ForEach(objectListInChunks, listOfObjects => 
    { 
     using (IDocumentSession ravenSession = GetRavenSession()) 
     { 
      listOfObjects.ForEach(x => ravenSession.Store(x)); 
      ravenSession.SaveChanges(); 
     } 
    }); 
} 

private static IDocumentSession GetRavenSession() 
{ 
    return _ravenDatabase.OpenSession(); 
} 
+0

謝謝! - 這可能是要走的路 – JanivZ 2012-04-08 05:54:21

2

您是否試圖將它全部保存在一個調用中? DocumentSession需要將所有傳遞給服務器的對象轉換爲單個請求。這意味着它可能會分配大量內存來寫入服務器。 通常我們建議批量約1,024件產品正在做大量保存。

+0

嗨Ayende和thx! 我可以問一下 - 當你說1024個物品時 - 它們的平均尺寸是多少?所以我可以估計可以處理多少個對象。 再次感謝 – JanivZ 2012-04-08 05:54:02

0

DocumentStore是一次性類,所以我通過在每個塊後部署實例來解決此問題。 I 高度懷疑這是運行操作的最有效的方式,但它將防止發生顯着的內存開銷。

我正在運行一種「刪除所有」操作,就像這樣。您可以在每個塊後面看到using塊將DocumentStoreIDocumentSession對象同時處理。

static DocumentStore GetDataStore() 
{ 
    DocumentStore ds = new DocumentStore 
    { 
     DefaultDatabase = "test", 
     Url = "http://localhost:8080" 
    }; 

    ds.Initialize(); 
    return ds; 
} 

static IDocumentSession GetDbInstance(DocumentStore ds) 
{ 
    return ds.OpenSession(); 
} 

static void Main(string[] args) 
{ 
    do 
    { 
     using (var ds = GetDataStore()) 
     using (var db = GetDbInstance(ds)) 
     { 
      //The `Take` operation will cap out at 1,024 by default, per Raven documentation 
      var list = db.Query<MyClass>().Skip(deleteSum).Take(5000).ToList(); 
      deleteCount = list.Count; 
      deleteSum += deleteCount; 

      foreach (var item in list) 
      { 
       db.Delete(item); 
      } 
      db.SaveChanges(); 
      list.Clear(); 
     } 
    } while (deleteCount > 0); 
}