改善NHibernate性能的最佳方法是什么?
我有一个使用NHibernate作为其ORM的应用程序,有时由于其如何访问数据而遇到性能问题。可以采取哪些措施来提高NHibernate的性能? (请限制为每个答案一个建议)
解决方案
回答
没有关于我们所看到的各种性能问题的详细信息,我只能提供一个概括:根据我的经验,大多数数据库查询性能问题是由于缺乏适当的索引而引起的。因此,我的第一个建议是检查查询计划中是否存在未编制索引的查询。
回答
NHibernate可能遇到的第一个也是最严重的性能问题是,是否要为创建的每个会话创建一个新的会话工厂。对于每个应用程序执行,只应创建一个会话工厂实例,而所有会话应由该工厂创建。
按照这些原则,只要有意义,我们就应该继续使用同一会话。这将因应用程序而异,但是对于大多数Web应用程序,建议每个请求一个会话。如果我们频繁放弃会话,则无法获得其缓存的好处。智能地使用会话缓存可以将具有线性(或者更糟)查询数目的例程更改为恒定数目,而无需进行大量工作。
同样重要的是,我们要确保延迟加载对象引用。如果不是这样,即使是最简单的查询,也可以加载整个对象图。仅出于某些原因不执行此操作,但是始终最好从延迟加载开始,然后根据需要切换回去。
这使我们急于获取,这与延迟加载相反。在遍历对象层次结构或者遍历集合时,很容易忘记正在执行的查询数量,最终导致查询数量成指数增长。可以使用FETCH JOIN在每个查询的基础上进行预先获取。在极少数情况下,例如,如果我们总是总是获取一对特定的表,请考虑为该关系关闭延迟加载。
与往常一样,SQL Profiler是查找运行缓慢或者重复进行的查询的好方法。在我的上一份工作中,我们拥有一个开发功能,该功能还可以计算每个页面请求的查询数。对例程的大量查询是最明显的指示,表明例程无法与NHibernate一起正常工作。如果每个例程或者请求的查询数量看起来不错,则可能是由于数据库调优了。确保我们有足够的内存来将执行计划和数据存储在缓存中,正确索引数据等。
我们遇到的一个棘手的小问题是SetParameterList()。该函数使我们可以轻松地将参数列表传递给查询。 NHibernate通过为传入的每个项创建一个参数来实现此目的。这为每种参数数量产生了不同的查询计划。我们的执行计划几乎总是从缓存中释放出来的。同样,许多参数也会大大降低查询速度。我们对NHibernate进行了自定义修改,将项目作为定界列表发送到单个参数中。该列表在SQL Server中由表值函数分隔,该表值函数被我们的黑客自动插入到查询的IN子句中。根据应用,可能还会有其他类似的地雷。 SQL Profiler是找到它们的最佳方法。
回答
NHibernate开箱即用即可生成非常快速的SQL。
我已经使用了一年,但还没有必要用它编写裸露的SQL。
我所有的性能问题都来自于规范化和缺乏索引。
回答
最简单的解决方法是检查查询的执行计划并创建适当的索引,尤其是在外键列上。如果我们使用的是Microsoft SQL Server,则"数据库引擎优化顾问"将对此提供很多帮助。
如果尚未(适当地)使用惰性加载,请开始。不需要时获取集合会浪费一切。
回答
"提高性能"一章介绍了这种方法以及其他提高性能的方法。
即使是简单的定时单元测试,分析也是第一步,以找出可以从中获得最大收益的地方
回答
对于集合,请考虑设置批处理大小以减少发出的选择语句的数量,有关详细信息,请参见提高性能部分。
我只能将我的答案限制在一个选项上吗?在这种情况下,我将选择我们实现NHibernate的二级缓存机制。
这样,对于映射文件中的每个对象,我们都可以定义缓存策略。二级缓存将已获取的对象保留在内存中,因此不会再次往返数据库。这是一个巨大的性能提升器。
目标是定义应用程序经常访问的对象。其中包括一般设置等。
关于nhibernate二级缓存及其实现方法,有很多信息可以找到。
回答
祝你好运 :)
缓存,缓存,缓存-我们是否正确使用了一级缓存[过早关闭会话,或者使用StatelessSession绕过了一级缓存]?我们是否需要为不经常更改的值设置简单的二级缓存?我们是否可以缓存查询结果集以加快不经常更改的查询的速度?
回答
[也可以配置-我们可以将项目设置为不可变的吗?我们可以重组查询以仅带回我们需要的信息并将其转换为原始实体吗?蝙蝠侠能否在到达水坝之前阻止谜语者? ...哦,对不起,被带走了。]
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(); } }
NHibernate的SessionFactory是一项昂贵的操作,因此一个好的策略是创建一个Singleton,以确保内存中只有一个SessionFactory实例:
protected void Application_Start() { NHibernateSessionManager.Instance.Initialize(); }
回答
然后,在Global.Asax Application_Startup中,可以对其进行初始化:
回答
通过识别何时从延迟加载切换到渴望获取慢速执行查询的时间来避免和/或者最小化Select N +1问题。
回答
除了为我们提供帮助的工具之外,没有其他建议:NH Prof(http://nhprof.com/)似乎很有希望,它可以评估我们对ORM框架的使用。这可能是我们调整NHibernate的一个很好的起点。
大量的空闲时间说了什么。
阅读文档的第19章"提高性能"。
NHibernate:http://nhibernate.info/doc/nhibernate-reference/performance.html
休眠:http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html
使用SQL事件探查器(或者与我们正在使用的数据库等效的探查器)查找长时间运行的查询。使用适当的索引优化那些查询。
对于几乎在应用程序的每个页面上使用的数据库调用,请使用CreateMultiQuery从单个数据库查询返回多个结果集。
段落数量不匹配