我有一个使用 NHibernate 作为其 ORM 的应用程序,有时由于它访问数据的方式,它会遇到性能问题。可以做哪些事情来提高NHibernate的性能?(请限制每个答案仅限一条推荐)

有帮助吗?

解决方案

使用 NHibernate 可能遇到的第一个也是最严重的性能问题是,如果您为创建的每个会话创建一个新的会话工厂。每次应用程序执行时只应创建一个会话工厂实例,并且所有会话都应由该工厂创建。

按照这些思路,只要有意义,您就应该继续使用同一个会话。这会因应用程序而异,但对于大多数 Web 应用程序,建议每个请求一个会话。如果您经常丢弃会话,则您将无法获得其缓存的好处。智能地使用会话缓存可以将具有线性(或更差)数量的查询的例程更改为恒定数量,而无需太多工作。

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

这给我们带来了急切的获取,与延迟加载相反。在遍历对象层次结构或循环遍历集合时,很容易忘记您正在进行的查询数量,并且最终会得到指数数量的查询。可以使用 FETCH JOIN 在每个查询的基础上完成预取。在极少数情况下,例如如果您总是获取联接的一对特定表,请考虑关闭该关系的延迟加载。

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

我们遇到的一个棘手的小问题是 SetParameterList()。该函数允许您轻松地将参数列表传递给查询。NHibernate 通过为传入的每一项创建一个参数来实现这一点。这会导致每个参数的查询计划都不同。我们的执行计划几乎总是从缓存中释放。此外,大量参数会显着减慢查询速度。我们对 NHibernate 进行了自定义修改,将项目作为单个参数中的分隔列表发送。该列表在 SQL Server 中由表值函数分隔,我们的 hack 自动将其插入到查询的 IN 子句中。根据您的应用程序,可能还有其他类似的地雷。SQL Profiler 是查找它们的最佳方式。

其他提示

NHibernate 的 SessionFactory 是一项昂贵的操作,因此一个好的策略是创建一个 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();
}

避免和/或尽量减少 选择N+1问题 通过识别何时从延迟加载切换到急切执行缓慢的查询。

没有推荐,但有一个工具可以帮助您:NH 教授( http://nhprof.com/ )看起来很有前途,它可以评估你对 ORM 框架的使用情况。它可能是您调整 NHibernate 的一个很好的起点。

由于没有关于您所看到的性能问题类型的任何具体信息,我只能提供一个概括:根据我的经验,大多数数据库查询性能问题都是由于缺乏适当的索引而引起的。因此,我建议的第一个操作是检查非索引查询的查询计划。

NHibernate 开箱即用地生成相当快的 SQL。我已经使用它一年了,但还没有用它编写裸 SQL。我所有的性能问题都来自于 正常化 以及缺乏索引。

最简单的解决方法是检查查询的执行计划并创建适当的索引,尤其是在外键列上。如果您使用的是 Microsoft SQL Server,“数据库引擎优化顾问”对此有很大帮助。

仅“每个答案一个推荐”?然后我会选择这个:

避免由于沿着两个或多个并行的多关联进行连接而导致重复连接(又名笛卡尔积);请改用 Exists-subqueries、MultiQueries 或 FetchMode“子选择”。

取自: Hibernate 性能调优技巧

我只能将我的答案限制为一个选项吗?在这种情况下我会选择你实现NHibernate的二级缓存机制。

这样,您就可以为映射文件中的每个对象定义缓存策略。二级缓存会将已检索的对象保留在内存中,因此不会再次往返数据库。这是一个巨大的性能助推器。

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

关于 nhibernate 二级缓存以及如何实现它,可以找到大量信息。

祝你好运 :)

缓存、缓存、缓存——您是否正确使用一级缓存(过早关闭会话,或使用 StatelessSession 绕过一级缓存)?您是否需要为不经常更改的值设置一个简单的二级缓存?您可以缓存查询结果集以加快不经常更改的查询吗?

[还有配置——你可以将项目设置为不可变吗?您能否重组查询以仅返回您需要的信息并将它们转换为原始实体?蝙蝠侠能在谜语人到达大坝之前阻止他吗?...噢,对不起,我走神了。]

分析是第一步 - 即使是简单的定时单元测试 - 找出可以取得最大收益的地方

对于集合,请考虑设置批处理大小以减少发出的 select 语句的数量 - 请参阅部分 提高绩效 欲了解详情

如果您还没有(适当地)使用延迟加载,请开始。当你不需要它们时获取集合是浪费一切。

章 提高绩效 描述了这种方法以及其他提高性能的方法。

大量空闲时间所说的话。

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

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

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

当然还有缓存。页面/控件的 OutputCache 指令。NHibernate 缓存数据。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top