什么是提高NHibernate性能的最佳方法?

我有一个应用程序使用NHibernate作为它的ORM,有时它会遇到性能问题,由于如何访问它的数据。 可以做什么样的事情来提高NHibernate的性能? (请将每个答案限制为一个build议)

你可以在NHibernate中遇到的第一个也是最显着的性能问题是如果你为每个创build的会话创build一个新的会话工厂。 应该为每个应用程序执行创build一个会话工厂实例,所有会话都应该由该工厂创build。

按照这些方法,只要有意义,您应该继续使用同一个会话。 这将因应用程序而异,但对于大多数Web应用程序,build议每个请求一个会话。 如果你经常丢掉会话,你没有获得caching的好处。 智能地使用会话高速caching可以将线性(或更差)的查询数量改变为常数,而无需太多工作。

同样重要的是,你要确保你懒加载你的对象引用。 如果不是这样,即使是最简单的查询,也可以加载完整的对象图。 只有某些原因不这样做,但最好从惰性加载开始并根据需要切换回去。

这带来了我们渴望的提取,与延迟加载相反。 在遍历对象层次结构或循环访问集合时,可能很容易丢失正在制作的查询数量,最终导致大量查询。 使用FETCH JOIN可以在每个查询的基础上完成预先提取。 在极less数情况下,例如,如果有一对特定的表,您总是获取连接,请考虑closures该关系的延迟加载。

与往常一样,SQL Profiler是查找运行缓慢或重复查询的好方法。 在我上一份工作中,我们有一个开发function,可以对每个页面的请求进行计数。 大量的例程查询是最明显的指标,你的例程不能很好地使用NHibernate。 如果每个例程或请求的查询数量看起来不错,那么可能是数据库调优; 确保你有足够的内存来存储caching中的执行计划和数据,正确的索引你的数据等。

我们遇到的一个棘手的小问题是SetParameterList()。 该function允许您轻松地将参数列表传递给查询。 NHibernate通过为每个传入的项目创build一个参数来实现这一点。这将导致每个参数的查询计划都不相同。 我们的执行计划几乎总是从caching中释放出来。 而且,许多参数可能会显着减慢查询速度。 我们做了一个NHibernate的自定义黑客发送项目作为一个单一的参数分隔列表。 该列表在SQL Server中由一个表值函数分开,我们的hack自动插入到查询的IN子句中。 根据您的应用,可能会有像这样的其他地雷。 SQL事件探查器是find它们的最佳方法。

NHibernate的SessionFactory是一个昂贵的操作,所以一个好的策略是创build一个Singleton,确保在内存中只有一个SessionFactory实例:

public class NHibernateSessionManager { private readonly ISessionFactory _sessionFactory; public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager(); private NHibernateSessionManager() { if (_sessionFactory == null) { System.Diagnostics.Debug.WriteLine("Factory was null - creating one"); _sessionFactory = (new Configuration().Configure().BuildSessionFactory()); } } public ISession GetSession() { return _sessionFactory.OpenSession(); } public void Initialize() { ISession disposeMe = Instance.GetSession(); } } 

然后在你的Global.Asax Application_Startup中,你可以初始化它:

 protected void Application_Start() { NHibernateSessionManager.Instance.Initialize(); } 

通过识别何时从延迟加载切换到提前执行查询,以避免和/或最小化selectN + 1问题 。

没有build议,只是一个工具来帮助你:NH教授( http://nhprof.com/ )似乎是有希望的,它可以评估你对ORM框架的使用。 它可以是你的NHibernate的一个很好的起点。

没有关于你所看到的性能问题的任何细节,我只能提供一个概括:根据我的经验,大多数数据库查询性能问题是由缺乏适当的索引引起的。 所以我的第一个行动的build议是检查您的查询计划非索引查询。

NHibernate生成相当快的SQL。 我已经使用了一年,还没有用它写裸露的SQL。 我的所有performance问题都来自正常化和缺乏索引。

最简单的解决方法是检查查询的执行计划并创build适当的索引,特别是在外键列上。 如果您正在使用Microsoft SQL Server,那么“数据库引擎优化顾问”将帮助您解决这个问题。

“每个答案只有一个build议”? 那么我会去这个:

由于沿着两个或多个并行的多对多关联进行连接,因此避免连接重复(AKA笛卡尔产品); 改用Exists-subqueries,MultiQueries或FetchMode“subselect”。

取自: Hibernate Performance Tuning Tips

我只允许我的答案限于一个选项? 在这种情况下,我会select你实现NHibernate的二级caching机制。

这样,对于映射文件中的每个对象,您都可以定义caching策略。 第二级caching将保持已经检索到的内存对象,因此不会再往返数据库。 这是一个巨大的性能提升。

您的目标是定义您的应用程序不断访问的对象。 其中包括一般设置等。

有关nhibernate二级caching的大量信息以及如何实现。

祝你好运 :)

caching,caching,caching – 您是否正确使用第一级caching[提前closures会话,或使用StatelessSession绕过第一级caching]? 您是否需要为不经常更改的值设置简单的二级caching? 你能caching查询结果集,以加快不经常更改的查询吗?

[也configuration – 你可以设置项目不可变? 你能重新调整查询,只取回你需要的信息,并把它们转换成原来的实体吗? 在蝙蝠侠到达大坝之前能够阻止“谜语”? 哦,对不起,已经被带走了。]

分析是第一步 – 甚至简单的定时unit testing – 找出哪里可以取得最大收益

对于集合,可以考虑设置批量大小以减less发布的select语句的数量 – 请参见提高性能以获取详细信息

如果您尚未使用延迟加载(适当),请启动。 当你不需要它们的时候拿取藏品就是浪费一切。

章节提高性能描述了这个和其他方法来提高性能。

什么批发期限说。

阅读文档“提高性能”的第19章。
NHibernate: http : //nhibernate.info/doc/nhibernate-reference/performance.html
hibernate: http : //docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

使用SQL事件探查器(或您正在使用的数据库的等效项)来查找长时间运行的查询。 使用适当的索引优化这些查询。

对于几乎在应用程序的每个页面上使用的数据库调用,使用CreateMultiQuery从单个数据库查询返回多个结果集。

当然,caching。 页面/控件的OutputCache指令。 NHibernatecaching数据。