Raven 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;
        }
        //}
    }

此代码被调用多次。在我得到大约50000个通过它的文档后,我得到了一个OutOfMemoryException。知道为什么吗?也许过一段时间我需要声明一个新的DocumentStore?

谢谢

**

  • 更新:

**

我最终使用Batch/Patch API来执行我需要的更新。您可以在此处查看讨论:https://groups.google.com/d/topic/ravendb/3wRT9c8Y-YE/discussion

基本上,由于我只需要更新对象上的1个属性,并且在考虑了ayendes关于将所有对象重新序列化回JSON的评论后,我做了这样的事情:

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;
    }

希望这能帮助。。。

非常感谢。

我刚刚为我当前的项目做了这件事。我把数据分块保存在一个新的会话中。这可能对你也有用。

请注意,这个示例显示了一次按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();
}

您是否试图在一次调用中保存所有内容?DocumentSession需要将传递给它的所有对象转换为对服务器的单个请求。这意味着它可能会为写入服务器分配大量内存。通常,我们建议您批量保存大约1024个项目。

DocumentStore是一个可丢弃类,所以我通过在每个块之后处理实例来解决这个问题。我非常怀疑这是运行操作的最有效方式,但它可以防止发生显著的内存开销。

我正在运行一种类似的"delete all"操作。你可以看到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);
}