0

我有以下代码行:

log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + "Check-1");

设置 setting = session.CreateQuery("from Setting s").UniqueResult< Setting>();

log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + "Check-2");

上面的代码在不到毫秒的时间内执行(Check-1 和 Check-2 中的时间相同,它以毫秒为单位测量时间,代码中未显示使用的标准)。

但在这种情况下:

IList<票>票= session.CreateQuery("从票").List<票>();

foreach(Ticket t in ticket)
{
t.Dosomething = 5;
log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + "Check-1"); 设置 setting = session.CreateQuery("from Setting s").UniqueResult< Setting>(); log4net.LogManager.GetLogger("m").Debug(DateTime.Now.ToString("hh:mm:ss.fff") + "Check-2");
}

上面的代码是处理大量数据的巨大处理代码的简化版本,我需要在 foreach 循环中进行另一个查询。forech 循环中的查询在 500 毫秒内执行。票证集合包含 15000 行。

我已经重构了代码(在 foreach 中没有查询),但是我很感兴趣,为什么单独执行相同的查询不需要时间来执行,但是如果在首先加载大量实体​​之后执行,它会变得如此缓慢?

但是在上面的相同场景中,如果我对第二个查询使用不同的会话,它会立即执行。

当我需要在大量实体的 foreach 循环中执行另一个查询时,有什么建议如何处理这种情况?

4

3 回答 3

2

NHibernate 默认跟踪会话中加载的对象(一级缓存)。当进行查询时,NHibernate 会检查某些加载的对象是否有可能影响查询结果的更改——这些更改必须刷新到数据库中,以便查询可以返回正确的结果。加载的对象越多,此过程所需的时间就越长。

NHibernate 和 ISession 针对加载的对象数量相对较少进行了优化,这不是问题。

这些是提高批处理场景性能的一些技巧:

  • 尝试将工作分成更小的部分,这些部分可以在单独的事务和会话中独立运行。

  • 如果您已将工作分成更小的部分,则可以在战略点(在每个独立部分之后)使用session.Flush()session.Clear()来刷新更改并将跟踪对象的数量保持在合理的水平。使用这种策略,所有部分都可以在同一个事务中运行。

  • 查看session.FlushMode以禁用自动刷新查询。使用FlushMode.CommitNever结合对 的显式调用Flush()。但是查询的结果可能不会反映之前在同一工作单元中执行的更改。

于 2013-03-06T09:37:41.707 回答
1

在迭代票证之前,尝试使用投影将票证加载到 DTO 中。Hibernate 会跟踪会话中所有已加载的对象,直到它刷新,使用投影仅加载您需要的数据将意味着 Hibernate 不需要加载和跟踪对象。

于 2013-03-05T16:05:05.893 回答
0

加入两个表并获得结果总是比获取第一个表记录、迭代然后获取第二个表记录更好。

给你更多的要求

于 2013-03-05T16:09:00.550 回答