NHibernate 延迟非常高

Posted

技术标签:

【中文标题】NHibernate 延迟非常高【英文标题】:NHibernate latency is very high 【发布时间】:2010-02-01 14:23:04 【问题描述】:

我将 NHibernate 用于 ORM,并将大量实体的加载合并到一个大查询中。

我实际上正在加载一个字典,大约 50 万个条目,每个单词都与其他单词相关。在我们的应用程序中在后台运行加载过程可能非常棘手,因为我们必须手动加载一个未按时加载的条目,因为任何时候都可能要求输入任何单词。我们唯一的要求是尽可能快地加载所有数据。 我也尝试过使用无状态会话,但出现了一个异常,即无状态会话无法获取集合(出于某种原因,可能与无状态会话没有缓存有关?)

问题在于,虽然在 SQLServer 中查询时间不超过 25 秒,但对于 ICriteria.List() 则需要 3 分钟以上。

我使用 NHProf 来分析加载过程,发现实体的创建是一项代价高昂的事情,它占用了 NHibernate 中的大部分加载时间。

我能做些什么来减少这种延迟吗?内存分配是昂贵的,还是数据的“填充”?

谢谢!

【问题讨论】:

【参考方案1】:

也许您应该考虑这样一个事实,即 NHibernate(与大多数 ORM 一样)并不特别适合(或不适合)这些类型的批量加载场景。您尝试加载、提供或获取多少行?你想做什么?预填充缓存?做批处理?

我的直觉是,您应该认真考虑应用程序的用途并相应地选择底层技术。也许您可以阐明您的意图/要求?

编辑好的,从你的 cmets 我明白你在这里想要做什么。我要做的第一件事是使用原始 ADO.NET 创建一个简单的原型来加载相同的数据,以感受使用标准数据访问和内存中集合可获得的最佳性能。接下来,摆弄不同的集合类型,看看在填充和搜索时什么表现良好。如果像这样加载数据仍然太慢,是时候开始研究其他加载数据的方法了:从本地数据文件基于文件、水合预序列化对象、某种形式的快速按需加载等。

【讨论】:

感谢您的快速回复!我正在尝试加载超过 500K 行,每行都是一个实体。每个实体都可以指向其他实体。我正在尝试使用所有这些相互关系尽快填充此列表。我没有向数据库写入任何内容,但是在尝试了延迟加载后,我发现它不适合我的需要。我能想到的下一个最好的事情是以某种生产者 - 消费者模式以某种方式将数据加载到不同的线程中,但我不知道你是如何做到的。有任何想法吗?您对其他技术有什么建议吗?谢谢! 我仍然不知道您为什么要加载这么多相互关联的实体。这使得提出建议变得困难。在后台加载数据是有意义的,但前提是您的应用程序可以在没有所有数据到位的情况下开始执行它需要执行的任何操作。简而言之,告诉我们您想要实现什么,您的要求是什么,也许我们可以给您一两个适当的建议。 当每个单词都与其他单词相关时,我实际上是在加载字典。在我们的应用程序中,后台的东西可能非常棘手,因为我们必须手动加载一个以前没有加载过的条目。问题是这些词中的任何一个都可以随时被要求。我们唯一的要求是尽可能快地加载所有数据。我也尝试过使用无状态会话,但出现了一个异常,即无状态会话无法获取集合... 我会用这个信息更新你原来的问题,这样更多的人会读到它。【参考方案2】:

将 500k 实体加载到 NHibernate 会话中不是一个好主意。会话是短暂的,并且包含相对较少数量的实体。

如果你想在 NHibernate 中进行这种批处理,你应该看看 StatelessSession 而不是普通的会话。在这种情况下,使用无状态会话很可能会显着提高性能。但是,当使用无状态会话时,您将失去 NHibernate 一级缓存的好处,例如更改跟踪。

有关 StatelessSession 的更多信息,请访问 nhibernate.info 的 this article 和 in the NH docs。

在这种情况下,我还建议您考虑直接使用 ADO.NET 而不是 NHibernate。我并不是说您应该将整个数据访问策略切换到 ADO.NET,但您可能需要考虑将 ADO.NET 用于批处理操作,而将 NHibernate 用于其他情况。

【讨论】:

谢谢。我尝试使用无状态会话,但出现以下错误:SessionException:“无状态会话无法获取集合”。为什么这是真的?有什么办法可以规避吗? 如果您确实需要加载填充了子集合的实体,那么 StatelessSession 也不适合,因为它会忽略集合(根据 NHForge 的文档)。其原因可能是 StatelessSession 在比普通会话更接近 ADO.NET 的级别上实现。在您的场景中,ADO.NET 似乎比 NHibernate 更好。【参考方案3】:

分析创建过程(例如使用 VS 性能分析器)应该可以准确地告诉您什么是昂贵的操作。如果您已经玩过延迟加载调整,那么我认为唯一好的解决方案是封装返回的列表,以便在几次迭代中分页返回较小的块。我不确定 NHibernate 是否支持像 JPA 那样的惰性结果列表(即在需要之前不从数据读取器加载实体)。

【讨论】:

以上是关于NHibernate 延迟非常高的主要内容,如果未能解决你的问题,请参考以下文章

在我的 NHibernate / SQLite 项目中提交非常慢

您是不是会将 NHibernate 用于具有部分无法控制的遗留数据库的项目?

NHibernate - 延迟初始化角色集合失败

如何在 NHibernate 中插入后启用延迟加载关系

NHibernate IQueryable 似乎不会延迟执行

NHibernate之(12):初探延迟加载机制