我有以下代码行:
log4net.LogManager.GetLogger(“m”)。Debug(DateTime.Now.ToString(“hh:mm:ss.fff”)+“Check-1”);
设置setting = session.CreateQuery(“来自设置s”)。UniqueResult<设置和GT;();
log4net.LogManager.GetLogger(“m”)。Debug(DateTime.Now.ToString(“hh:mm:ss.fff”)+“Check-2”);
上面的代码执行时间小于毫秒(Check-1和Check-2中的时间相同,它以毫秒为单位测量时间,并且代码中未显示使用的条件。)
但在这种情况下:
的IList<票> tickets = session.CreateQuery(“来自Ticket”)。列表<票>();
foreach(门票票)
{
t.Dosomething = 5;
log4net.LogManager.GetLogger(“m”)。Debug(DateTime.Now.ToString(“hh:mm:ss.fff”)+“Check-1”); 设置setting = session.CreateQuery(“来自设置s”)。UniqueResult<设置>(); log4net.LogManager.GetLogger(“m”)。Debug(DateTime.Now.ToString(“hh:mm:ss.fff”)+“Check-2”);
}
上面的代码是处理大量数据的巨大处理代码的简化版本,我需要在foreach循环中进行另一个查询。 forech循环中的查询在500ms内执行。故障单集合包含15000行。
我已经重新考虑了代码(在foreach中没有查询),但我感兴趣的是,如果单独执行相同的查询没有时间执行,但如果在首先加载大量实体后执行,它会变得如此之慢?
但是在上面的相同场景中,如果我在第二个查询中使用不同的会话,它会立即执行。
当我需要在大量实体的foreach循环中执行另一个查询时,如何处理这些情况的任何建议?
答案 0 :(得分:2)
NHibernate默认跟踪会话中加载的对象(第一级缓存)。在进行查询时,NHibernate会检查某些加载的对象是否有可能影响查询结果的更改 - 必须将这些更改刷新到数据库,以便查询可以返回正确的结果。加载的对象越多,此过程所需的时间就越长。
NHibernate和ISession针对拥有相对较少数量的已加载对象进行了优化,这不是问题。
这些是提高批处理方案性能的一些技巧:
尝试将作品分成可以在单独的交易和会话中独立运行的较小部分。
如果您将工作划分为较小的部分,则可以在战略要点(每个独立部分之后)使用session.Flush()
和session.Clear()
来清除更改并保留跟踪对象的数量合理的水平。使用此策略,所有部件都可以在同一事务中运行。
查看session.FlushMode
以禁用自动刷新查询。使用FlushMode.Commit
或Never
结合显式调用Flush()
。但查询结果可能无法反映早先在同一工作单元中执行的更改。
答案 1 :(得分:1)
尝试使用投影将票证加载到DTO中,然后再迭代它们。 Hibernate跟踪会话中的所有已加载对象,直到它被刷新为止,使用投影加载您需要的数据将意味着Hibernate不需要加载和跟踪对象。
答案 2 :(得分:0)
最好连接两个表并获取结果,而不是获取第一个表记录,迭代然后获取第二个表记录。
满足您的更多要求