Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to improve performance of NHibernate? [closed]

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)

like image 674
Ray Avatar asked Sep 15 '08 21:09

Ray


People also ask

What does NHibernate flush do?

Flushing synchronizes the persistent store with in-memory changes but not vice-versa. Note that for all NHibernate ADO.NET connections/transactions, the transaction isolation level for that connection applies to all operations executed by NHibernate!

Why is NHibernate used?

NHibernate is an ORM (Object Relational Mapper). Its purpose is to map objects in your OO application to tables in a database for persistence. Why would you need it? Because it can save you from writing a lot of tedious ADO.NET code.

What is fetch in NHibernate?

Fetching strategies. A fetching strategy is the strategy NHibernate will use for retrieving associated objects if the application needs to navigate the association. Fetch strategies may be declared in the O/R mapping metadata, or overridden by a particular HQL or Criteria query.


2 Answers

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:

   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:

protected void Application_Start() {     NHibernateSessionManager.Instance.Initialize(); } 
like image 28
David P Avatar answered Sep 22 '22 23:09

David P


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.

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.

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.

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.

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.

like image 182
Chuck Avatar answered Sep 24 '22 23:09

Chuck