简体   繁体   English

实体框架(EF)OutOfMemoryException

[英]Entity Framework (EF) OutOfMemoryException

I have > 67000 records coming to my system from another source. 我有来自其他来源的> 67000条记录来到我的系统。 After applying business rules to those records I have to store them to the database. 将业务规则应用于这些记录后,我必须将它们存储到数据库中。 I use following code for doing that: 我使用以下代码执行此操作:

        using (var context = new MyEntities())
        {
            var importDataInfo = context.ImportDataInfoes.First(x => x.ID == importId);

            importedRecords.ForEach(importDataInfo.ValuationEventFulls.Add);

            context.SaveChanges();
        }

After executing code I am getting following error (OutOfMemoryException) 执行代码后,我收到以下错误(OutOfMemoryException)

    Error in executing code|Exception of type 'System.OutOfMemoryException' was thrown.*   at System.Data.Mapping.Update.Internal.KeyManager.<WalkGraph>d__5.MoveNext()
   at System.Data.Mapping.Update.Internal.KeyManager.GetPrincipalValue(PropagatorResult result)
   at System.Data.Mapping.Update.Internal.UpdateCompiler.GenerateValueExpression(EdmProperty property, PropagatorResult value)
   at System.Data.Mapping.Update.Internal.UpdateCompiler.BuildSetClauses(DbExpressionBinding target, PropagatorResult row, PropagatorResult originalRow, TableChangeProcessor processor, Boolean insertMode, Dictionary`2& outputIdentifiers, DbExpression& returning, Boolean& rowMustBeTouched)
   at System.Data.Mapping.Update.Internal.UpdateCompiler.BuildInsertCommand(PropagatorResult newRow, TableChangeProcessor processor)
   at System.Data.Mapping.Update.Internal.TableChangeProcessor.CompileCommands(ChangeNode changeNode, UpdateCompiler compiler)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.<ProduceDynamicCommands>d__0.MoveNext()
   at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
   at System.Data.Mapping.Update.Internal.UpdateCommandOrderer..ctor(IEnumerable`1 commands, UpdateTranslator translator)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)

I am using EF 4.0. 我使用的是EF 4.0。

My question is there is limitation on number of records to save? 我的问题是要保存的记录数量有限制吗? What is the best practice to save big number of records (save them in chunks? what about transactions?). 保存大量记录的最佳做法是什么(将它们保存在块中?交易怎么样?)。

Thanks everybody in advance. 提前谢谢大家。

You would probably want to send that data down in batches of probably 1024 records at a time. 您可能希望一次批量发送大约1024条记录的数据。

You could wrap the loop that batches the records in a transaction so you could rollback the entire sequence if desired. 您可以包装在事务中批处理记录的循环,以便您可以根据需要回滚整个序列。 Do note that this transaction will most likely escalate to a distributed transaction. 请注意,此事务很可能会升级为分布式事务。

Distributed transactions can only be applied against a server that has the Microsoft Distributed Transaction Coordinator (MS-DTC) service running. 分布式事务只能应用于运行Microsoft分布式事务处理协调器(MS-DTC)服务的服务器。 There is a notable performance penalty when working distributed transactions. 在分布式事务处理时,性能会受到显着影响。

In general, .NET is limited to addressing 2GB of memory in a single collection or other object. 通常,.NET仅限于在单个集合或其他对象中处理2GB内存。 This is because even in a 64-bit environment, indexers use 32-bit integers (with a max value of 2 billion and change). 这是因为即使在64位环境中,索引器也使用32位整数(最大值为20亿并且更改)。 Even for simple data types like integers, the size of a single int means that only 500 million ints can be stored in a single array. 即使对于像整数这样的简单数据类型,单个int的大小意味着只能在单个数组中存储5亿个int。 For larger value types like structures, the maximum number of elements of a collection gets really small. 对于像结构这样的较大值类型,集合的最大元素数量非常小。

If you're in a 32-bit environment like Windows XP, there are even lower limits; 如果你处于像Windows XP这样的32位环境中,那么它的限制甚至更低; the maximum memory space for the ENTIRE PROGRAM cannot be greater than 2GB. 整个程序的最大内存空间不能超过2GB。 This places some pretty high restrictions on an ETL like yours, and I would not be surprised at all that your program is running out of memory trying to process 67k in-memory records at once. 这对像你这样的ETL有一些相当高的限制,我不会对你的程序内存耗尽试图同时处理67k内存中的记录感到惊讶。

The solution is to handle records in smaller batches if you can. 解决方案是尽可能小批量处理记录。 Try constructing a statement based on the ID, where you return the top 100 records where the ID (hopefully auto-generated) is greater than the largest ID you've already retrieved. 尝试根据ID构建一个语句,返回前100条记录,其中ID(希望自动生成)大于您已检索的最大ID。 Once a record is processed, dispose of it (or just orphan it and let the GC do its job). 处理完记录后,处理它(或者只是孤立它并让GC完成它的工作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM