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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/67103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 09:51:56  来源:igfitidea点击:

What is the best way to improve performance of NHibernate?

.netperformancenhibernateormdata-access-layer

提问by Ray

I have an application that uses NHibernate as its ORM and sometimes it experiences performance issues due to how the data is being accessed by it. What kind of things can be done to improve the performance of NHibernate? (Please limit to one recommendation per answer)

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

采纳答案by Chuck

The first and most dramatic performance problem that you can run into with NHibernate is if you are creating a new session factory for every session you create. Only one session factory instance should be created for each application execution and all sessions should be created by that factory.

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

Along those lines, you should continue using the same session as long as it makes sense. This will vary by application, but for most web applications, a single session per request is recommended. If you throw away your session frequently, you aren't gaining the benefits of its cache. Intelligently using the session cache can change a routine with a linear (or worse) number of queries to a constant number without much work.

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

Equally important is that you want to make sure that you are lazy loading your object references. If you are not, entire object graphs could be loaded for even the most simple queries. There are only certain reasons not to do this, but it is always better to start with lazy loading and switch back as needed.

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

That brings us to eager fetching, the opposite of lazy loading. While traversing object hierarchies or looping through collections, it can be easy to lose track of how many queries you are making and you end up with an exponential number of queries. Eager fetching can be done on a per query basis with a FETCH JOIN. In rare circumstances, such as if there is a particular pair of tables you always fetch join, consider turning off lazy loading for that relationship.

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

As always, SQL Profiler is a great way to find queries that are running slow or being made repeatedly. At my last job we had a development feature that counted queries per page request as well. A high number of queries for a routine is the most obvious indicator that your routine is not working well with NHibernate. If the number of queries per routine or request looks good, you are probably down to database tuning; making sure you have enough memory to store execution plans and data in the cache, correctly indexing your data, etc.

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

One tricky little problem we ran into was with SetParameterList(). The function allows you to easily pass a list of parameters to a query. NHibernate implemented this by creating one parameter for each item passed in. This results in a different query plan for every number of parameters. Our execution plans were almost always getting released from the cache. Also, numerous parameters can significantly slow down a query. We did a custom hack of NHibernate to send the items as a delimited list in a single parameter. The list was separated in SQL Server by a table value function that our hack automatically inserted into the IN clause of the query. There could be other land mines like this depending on your application. SQL Profiler is the best way to find them.

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

回答by David P

NHibernate's SessionFactory is an expensive operation so a good strategy is to creates a Singleton which ensures that there is only ONE instance of SessionFactory in memory:

NHibernate 的 SessionFactory 是一项昂贵的操作,因此一个好的策略是创建一个单例,以确保内存中只有一个 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();
        }
    }

Then in your Global.Asax Application_Startup, you can initialize it:

然后在您的 Global.Asax Application_Startup 中,您可以对其进行初始化:

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

回答by Ray

Avoid and/or minimize the Select N + 1 problemby recognizing when to switch from lazy loading to eager fetching for slow performing queries.

通过识别何时从延迟加载切换到对执行缓慢的查询的急切获取,避免和/或最小化Select N + 1 问题

回答by MatthieuGD

No a recommendation but a tool to help you : NH Prof ( http://nhprof.com/) seems to be promising, it can evaluate your use of the ORM framework. It can be a good starting point for your tunning of NHibernate.

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

回答by Mike Monette

Without any specifics about the kinds of performance issues you're seeing, I can only offer a generalization: In my experience, most database query performance issues arise from lack of proper indices. So my suggestion for a first action would be to check your query plans for non-indexed queries.

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

回答by gnome26

"One recommendation per answer" only? Then I would go for this one:

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

Avoid join duplicates (AKA cartesian products) due to joins along two or more parallel to-many associations; use Exists-subqueries, MultiQueries or FetchMode "subselect" instead.

避免连接重复(AKA 笛卡尔积),因为连接沿两个或多个平行的多关联;改用 Exists-subqueries、MultiQueries 或 FetchMode“subselect”。

Taken from: Hibernate Performance Tuning Tips

摘自:Hibernate 性能调优技巧

回答by Eric Lathrop

NHibernate generates pretty fast SQL right out of the box. I've been using it for a year, and have yet to have to write bare SQL with it. All of my performance problems have been from Normalizationand lack of indexes.

NHibernate 开箱即用地生成非常快的 SQL。我已经使用它一年了,还没有用它编写裸 SQL。我所有的性能问题都来自标准化和缺乏索引。

The easiest fix is to examine the execution plans of your queries and create proper indexes, especially on your foreign key columns. If you are using Microsoft SQL Server, the "Database Engine Tuning Advisor" helps out a lot with this.

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

回答by lotsoffreetime

If you're not already using lazy loading (appropriately), start. Fetching collections when you don't need them is a waste of everything.

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

Chapter Improving performancedescribes this and other ways to improve performance.

提高性能一章描述了这种和其他提高性能的方法。

回答by Richard

Profiling is the first step - even simple timed unit tests - to find out where the greatest gains can be made

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

For collections consider setting the batch size to reduce the number of select statements issued - see section Improving performancefor details

对于集合,请考虑设置批处理大小以减少发出的 select 语句的数量 -有关详细信息,请参阅提高性能部分

回答by Hace

I am only allowed to limit my answer to one option? In that case I would select that you implement the second-level cache mechanism of NHibernate.

我只能回答一个选项?在这种情况下,我会选择您实现 NHibernate 的二级缓存机制。

This way, for each object in your mapping file you are able to define the cache-strategy. The secondlevel cache will keep already retrieved objects in memory and therefore not make another roundtrip to the database. This is a huge performance booster.

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

Your goal is to define the objects that are constantly accessed by your application. Among those will be general settings and the like.

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

There is plenty of information to be found for nhibernate second level cache and how to implement it.

有很多关于 nhibernate 二级缓存以及如何实现它的信息。

Good luck :)

祝你好运 :)