使用NHibernate处理大型结果集

时间:2016-10-11 08:03:36

标签: c# performance nhibernate

我有以下任务要做:计算所有有效帐户的利息。在过去,我使用Ado.Net和存储过程来做这样的事情。 这次我试图用NHibernate做到这一点,因为用纯POCO似乎可以更容易地完成复杂的算法。 所以我想做以下(伪代码): foreach account in accounts calculate interest save account with new interest 我知道NHibernate不是为处理大数据量而设计的。对我来说,有可能组织这样一个循环,而不必同时在内存中拥有所有帐户。 为了最大限度地减少内存使用,我将IStatelessSession用于外部循环而不是普通ISession。 我尝试过Ayende提出的方法。有两个问题:

     
  • CreateQuery正在使用"魔术字符串";
  •  
  • 更重要的是:它没有按照描述的方式工作。

我的程序工作但是在打开Odbc跟踪之后我在调试器中看到所有提取都是在第一次执行.List中的lambda表达式之前完成的。 我找到了另一种解决方案:session.Query返回我在foreach中使用的.AsEnumerable()。还有两个问题:

     
  • 我更喜欢IQueryOver而不是IQueryable
  •  
  • 仍然没有按照描述的方式工作(在首次计算利息之前的所有提取)。

我不知道为什么,但IQueryOver没有AsEnumerable。它也没有List方法与参数(如CreateQuery)。我已经尝试了.Future,但又一次:

     
  • Future的文档没有描述流媒体功能
  •  
  • 仍然没有按照我的需要工作(在首次计算利息之前进行所有提取)。

总结:来自Ado.Net的NHibernate与dataReader.Read()有任何等价物吗?

我对纯NHibernate方法的最佳替代方法是使用dataReader.Read()进行主循环,然后使用来自Ado.Net循环的Load帐户。但是性能会受到影响 - 通过密钥读取每个帐户比在外循环中完成的提取序列要慢。

我使用的是NHibernate 4.0.0.4000版。

1 个答案:

答案 0 :(得分:1)

虽然NH的设计并未考虑到大型处理,但您始终可以通过应用层批处理来规避此限制。我发现,根据相关实体的对象图的大小,在将一定数量的对象加载到内存后,性能将受到影响(在一个小项目中,我可以加载100.000个对象,性能仍然可以接受,在另一个只有1500个对象,任何额外的Load()都会抓取)。

过去我使用分页处理批处理,当IStatelessSession结果集太差时(因为他们不加载代理等)。

因此,您在开始时进行计数查询,组成一些任意批量大小,然后开始对批处理进行处理。通过这种方式,您可以巧妙地避免n + 1选择问题,假设对于每个批处理,您明确地获取所需的所有内容。

需要注意的是,为了使其有效工作,您需要在完成后从ISession中逐出每个批处理的已处理实体。这意味着您必须在每个批次上提交事务。如果您可以使用多次刷新+提交,那么这可能适合您。

否则你将不得不去IStatelessSession尽管那里没有懒惰的查询。 "来自Books"意味着"从dbo.Books"中选择*或类似的东西,所有结果都被提取到内存中。