1

I am having a performance issue on a system I'm working on when I try to load ~7700 records from the DB. NHB takes 10x longer to do its load, vs the same query using SqlDataReader. Obviously there is going to be some performance overhead using NHB, but 10x the time vs ADO.NET seems excessive. From what I can determine, NHB is the issue, specifically in how it handles the collections which hang off the entity.

We have this general issue across our system when we try to load large(ish) numbers of entities, when the entities themselves have a large number of collections hanging off them.

I'm hoping someone can lend some advice on how I can improve this issue.

The query is simple.

var employees = session.QueryOver<Employee>().List();

There are no Select n+1 / lazy fetching issues occurring either. The single DB statement issued is effectively select * from employee.

I wont post up the full fluent mapping for the entity unless someone asks, as its quite large, but its fairly standard. The entity in question consists of:

24 fields
3 1-1 Relationships
86 1-* Relationships

Extract:

HasMany(e => e.Roles)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.AllDeleteOrphan()
.Fetch.Select()
.Inverse()
.LazyLoad()
.KeyColumns.Add("[EmployeeId]")
.Cache.ReadWrite().IncludeAll();

Below are the average timings of 5 tests executed 1000 times. The timing starts / stops when I create/dispose of the NHB session, it does not include creation of the session factory.

00:00:00.7080910 - 7677 records loaded/entity instantiation/manual map using ADO.NET
00:00:01.6055084 - 7677 entities - session - Fields Only
00:00:01.7866198 - 7677 entities - session - Fields + 1-1 Relationships
00:00:11.3384154 - 7677 entities - session - Fields + 1-1 Relationships + 1-* Relationships
00:00:10.9083002 - 7677 entities - stateless session - Fields + 1-1 Relationships + 1-* Relationships

Just to be clear, this is not a DB/network/lazy fetching issue. IMO the issue seems to be in how NHB hydrates the entities.

Edit:Even though the fNHB mapping specifies caching, its disabled in the session factory. I explicitly removed them from the mapping files to verify, and the durations are unchanged.

I've also used ANTS to profile the code, and it seems the majority of time is spent in the TwoPhaseLoad.InitializeEntity. (Disregard the other 50% of the time, which is not shown below. Its nHibernates session factory, which is not the cause of the performance issue)

ANTS Performance Profile Capture

Environment: nHibernate 3.3.1.4000, fnHibernate 1.3.0.733, MS SQL Server 2008, c# 4.0, Windows 7-64.

4

1 回答 1

-1

编写查询时,您必须将 .FetchMany(Func lambda) NHibernate 扩展包括到 IQueryable。

例如,如果您使用 Bars 查询一对多的 Foos:

class Foo 
{
    IList<Bar> Bars
}

代替

session.Query<Foo>().ToList();(全部)

你应该写

session.Query<Foo>().FetchMany( src => src.Bars ).ToList();

这将告诉 nhibernate 在每一行上获取连接而不是获取选择。

于 2013-09-11T13:02:21.343 回答