nHibernate3; retrieving 4xxx records out of an EAV data schema. When nHibernate, or .NET, goes to initialize those collections for the first time, we\'re seeing a severe pen
One option is to enable batch-size on your collections. I assume those are lazy, and with batch size enabled, it would try to fetch collections for multiple entities in a single roundtrip.
It doesn't make a difference if you fetch 1 entity with one collection, but can make a huge difference if you select 1000 entities which all has one collection. Using a batch-size of 1000 would result in 2 queries instead of 1001.
Tried to find some documentation, but only found this example:
nhibernate alternates batch size
Using join strategies in your case would result in gigantic resultsets so that is not a good option. A better option would be to use FetchMode.Select which would explicitly force your collections to be loaded in a subsequent roundtrip.
Another thing that could improve performance is setting:
Session.FlushMode = FlushMode.Never;
Which disable automatic flushing of your scope. This is useful if all you actually do is reading data, not modifying it. However, you would see calls to IsDirty or any other check for dirty objects in your callstack.
If you are using this session only for reporting, you have to use Stateless Sessions: http://nhforge.org/blogs/nhibernate/archive/2008/10/30/bulk-data-operations-with-nhibernate-s-stateless-sessions.aspx
1) A serialized mapping will only help to reduce the time required to build the SessionFactory. If the above query is not the first access to the database, it will not accomplish anything in that regard.
2) Set FetchMode needs to be applied to the children, like this:
var products = ((HandleSession)_handleSession).Session.CreateCriteria(typeof(Product))
.SetFetchMode("ProductChildren", FetchMode.Eager)
.List<Product>()
.AsEnumerable();
3) This looks like a N+1 problem, if I interpret the methods in the Screenshots correctly. Are you transforming the Products
in your query result to a list of ProductDTOs? If so, it seems as if the child collections are lazy loaded from the DB within a loop.
Edit:
In order to combat the N+1 Select, we will have to tell NHibernate to load everything beforehand, preferably with Futures. Here is a potential solution that basically fetches all your data from the db with a handful of Select-statements. I did not include any Where-conditions. Those you would have to add accordingly.
// any where-condition will have to be applied here and in the subsequent queries
var products = session.QueryOver<Product>()
.Future();
var products2 = session.QueryOver<Product>()
.Fetch(p => p.ProductType).Eager
.Future();
var products3 = session.QueryOver<Product>()
.Fetch(p => p.ProductAttributes).Eager
.Future();
var products4 = session.QueryOver<Product>()
.Fetch(p => p.ProductGroups).Eager
.Future();
// Here we execute all of the above queries in one roundtrip.
// Since we already have all the data we could possibly want, there is no need
// for a N+1 Select.
return new ProductList(products.Select(p => p.ToProductContract()));