Thoughts on NHibernate performance: stateless sessions
This is the second part in my series of "Thoughts on NHibernate performance". I recommend that you read the first post (insert link) because I will reuse things from that post. In this post I am going to talk about using a stateless session for inserting records to the database by using NHibernate. This is something I didn't talked about in the previous post simply because otherwise the post would become too long. You can find the updated version of the code on my Github account. I won't go in detail about the code only for the new parts.
Stateless session
When you start a new NHibernate session it will automatically track the entities that are retrieved from database. For instance take a look at the following code:
What do you think will happen ? Take a brief moment, no need to rush. When this code is executed the code will result into an update to the database. Why is this ? Because from the moment we fetch the entity, NHibernate starts tracking the changes. So when we change the value of a property on the entity, NHibernate will mark the entity as dirty. When the transaction is committed NHibernate will know which entities, or properties, needs to be updated. This is called a statefull session or session. Throughout this post I will use the term statefull session.
Now you have to know that all this tracking is done in memory and the question is "will performance be better when we use a stateless session". I took the tests, from my previous post, and run them against a stateless session to see the results. Note: this numbers are just an indication. The tests are performed on my local machine.
Before we go to the tests I will show you the code. I created a new class which contains the specific methods for the inserting objects with stateless session.
In the above method a stateless session is created. This has some implications because a stateless session has other methods. For instance when saving the object you don't use the method Save() but you use Insert() instead. The methods Update() and Delete() don't exist on a stateless session object. Actually a stateless session is much closer to ADO.NET than a statefull session.
Now let's take a look at the tests.
Test: 200 records
For the first test I inserted 200 records into the database. I have used the same 3 methods of my previous blogpost. Here are the results for the statefull session:
This are the results when using a stateless session:
When comparing the results you will only see a small improvement. For the first method there is 3ms gain and 2 other only 1ms. Looking at these results you would say that going stateless is not really an improvement. For this reason I created 2 extra tests with much more records.
Test: 2.000 records
In this next test I will insert 2.000 records. Let's take a look at the results
Results for the statefull session (2.000 records):
Results for the stateless session (2.000 records):
You will notice that the difference is much bigger then when inserting 200 records. The first method has a difference of 57ms. The other 2 methods are only 27ms (for HiLo) and 51ms (for Guid). The GUID results are pretty high for this test run.
Test: 10.000 records
In this final test I will insert 10.000 records.
Results for the statefull session (10.000 records):
Results for the stateless session (10.000 records):
When we compare the test results the differences are even bigger then with the previous test. For the first method you will see a difference of 336ms. It' safe to say that when inserting large volumes of data you should consider using a stateless session.
Summary
Below you will see a table with all the query results. Note: this numbers are just an indication. The tests are performed on my local machine.
DB generated | HiLo generated | GUID generated | ||||
---|---|---|---|---|---|---|
SF | SL | SF | SL | SF | SL | |
200 records | 95ms | 98ms | 17ms | 16ms | 17ms | 15ms |
2.000 records | 905ms | 848ms | 157ms | 130ms | 194ms | 143ms |
10.000 records | 4574ms | 4238ms | 767ms | 639ms | 839ms | 707ms |
Something that you will notice is that using a stateless session becomes faster when inserting a large number of records. In the test with 200 records you can see that the differences are actually very small. It's max 3 milliseconds but when we take a look a the test with 2.000 and 10.000 records the difference become greater and greater. Meaning performance is better when inserting a large number of objects. As I said at the summary of my previous post NHibernate is not the best tool to use when doing ETL operations so when inserting 1000 of records take a look at the tools as SqlBulkCopy.
I hope you'll find this post useful.