nHibernate performance issue when loading large collections - nhibernate

(just to make clear: my app isn't really about employees and departments. I just use these terms for example's sake).
Each department has an employees collection, which is lazily-loaded. Whenever I add a new employee I want to make sure It doesn't already exist in the collection, so I load the collection to memory and perform the check on it.
Problem is- in production environment, I have some departments with 10,000+ employees.
I found that fetching the collection and then saving the new employee takes A LOT of time.
I've done a little experment, in which I copied the exact same select statement generated by nH to ADO.Net SQLDataAdapter. Here are the results:
***16:04:50:437*** DEBUG NHibernate.SQL - SELECT ... FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=#p0;#p0 = 2
***16:05:00:250*** DEBUG NHibernate.SQL - SELECT ... FROM dbo.TableD codeshared0_ left outer join dbo.[Department] department1_ on codeshared0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE codeshared0_.Employee_id in (select emp0_.Id FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=#p0);#p0 = 2
16:05:04:984 DEBUG NHibernate.SQL - Reading high value:select next_hi from dbo._uniqueKey with (updlock, rowlock)
16:05:05:078 DEBUG NHibernate.SQL - Updating high value:update dbo._uniqueKey set next_hi = #p0 where next_hi = #p1;#p0 = 10686, #p1 = 10685
***16:05:05:328*** DEBUG MyApp.Managers - commiting
16:05:12:000 DEBUG NHibernate.SQL - INSERT INTO dbo.[Employee] (...) VALUES (#p0, #p1, #p2, #p3, #p4, #p5, #p6, #p7, #p8, #p9);#p0 = 23/04/2011 04:04:49, #p1 = 23/04/2011 03:34:49, #p2 = 23/04/2011 04:04:49, #p3 = 23/04/2011 03:34:49, #p4 = '', #p5 = False, #p6 = 433, #p7 = NULL, #p8 = 2, #p9 = 10685
16:05:12:140 DEBUG NHibernate.SQL - UPDATE dbo.[Employee] SET Department_id = #p0 WHERE Id = #p1;#p0 = 2, #p1 = 10685
16:05:12:343 DEBUG MyApp.Managers - success
16:05:12:359 DEBUG MyApp.Tests - ------------------------------------------------------------
16:05:12:359 DEBUG MyApp.Tests - Finished nHib stuff- now switching to ADO
16:05:12:359 DEBUG MyApp.Tests - starting SQL: SELECT ... FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=2
16:05:14:750 DEBUG MyApp.Tests - total rows received: 10036
16:05:14:750 DEBUG MyApp.Tests - SQL: SELECT ... FROM dbo.TableD codeshared0_ left outer join dbo.[Department] department1_ on codeshared0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE codeshared0_.Employee_id in (select emp0_.Id FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=2)
16:05:15:250 DEBUG MyApp.Tests - total rows received: 2421
as you can see- fetching takes ~15 secs with nH, compared to ~2 secs with ADO.Net.
From researching around a bit I know that nH probably isn't meant to be used to store that many items in session. Can you think of any other possible reason for this problem, or of another suggestion other than filtering the Employees at the DB level?
thanks
--EDIT--
Following the below suggestions i've tried using Reflection Optimizer (made no difference), and IStatelessSession for loading my collection (throws an exception- collections cannot be fetched by a stateless session.).
I think my code in the Department class will have to change from the clean:
if (this.Employees.Contains(emp))
{
...
}
to this 'dirtier' version:
var employeesRepository = IOCContainer.Get<IEmployeesRepository>();
if (employeesRepository.EmployeeExists(this,emp))
{
...
}
anyone has a better suggestion?

There is no reason for you to load all the empoyees to memory. you should write a query
using HQL/Critiria API/Linq to NHibernate to check if the employee already existing in the DB.
for example:
var existingEmpoyee = session.Query<Employee>()
.Where(e => e.Equals(newEmployee))
.FirstOrDefault();
if(existingEmployee != null)
// Insert new employee to DB

I would use a StatelessSession and batch optimization.
The session will keep track of all the
loaded objects, and if we load a lot
of data, it will eventually blow out
with an out of memory exception.
Luckily, NHibernate has a ready made
solution for this, the stateless
session. The code now looks like this:
using (IStatelessSession s = sessionFactory.OpenStatelessSession())
{
var books = new ActionableList<Book>(book => Console.WriteLine(book.Name));
s.CreateQuery("from Book")
.List(books);
}
The stateless session, unlike the
normal NHibernate session, doesn’t
keep track of loaded objects, so the
code here and the data reader code are
essentially the same thing.
For batch optimization and more: NHibernate performance tricks.

hmmmm. may be its too much, and actually - i'd expect an "lazy=extra" ISet to behave like this, but you can write your own "extra lazy" ISet.
if you didn't encounter an extra lazy collection - its a collection that, for example, when you ask its count, it doesn't fetch everything but issues a count query.
your extra lazy ISet could issue an exists query whenever you try to add something.
If you implement this, your code would be clean and you could submit the code to nhibernate core.
you should however think about add range, and be careful not to issue N queries
good luck.

Related

Need help optimizing this tSQL Query

I'm definitely not a DBA and unfortunately we don't have a DBA to consult within at our company. I was wondering if someone could give me a recommendation on how to improve this query, either by changing the query itself or adding indexes to the database.
Looking at the execution plan of the query it seems like the outer joins are killing the query. This query only returns 350k results, but it takes almost 30 seconds to complete. I don't know much about DB's, but I don't think this is good? Perhaps I'm wrong?
Any suggestions would be greatly appreciated. Thanks in advance.
As a side note this is obviously being create by an ORM and not me directly. We are using Linq-to-SQL.
SELECT
[t12].[value] AS [DiscoveryEnabled],
[t12].[value2] AS [isConnected],
[t12].[Interface],
[t12].[Description] AS [InterfaceDescription],
[t12].[value3] AS [Duplex],
[t12].[value4] AS [IsEnabled],
[t12].[value5] AS [Host],
[t12].[value6] AS [HostIP],
[t12].[value7] AS [MAC],
[t12].[value8] AS [MACadded],
[t12].[value9] AS [PortFast],
[t12].[value10] AS [PortSecurity],
[t12].[value11] AS [ShortHost],
[t12].[value12] AS [SNMPlink],
[t12].[value13] AS [Speed],
[t12].[value14] AS [InterfaceStatus],
[t12].[InterfaceType],
[t12].[value15] AS [IsUserPort],
[t12].[value16] AS [VLAN],
[t12].[value17] AS [Code],
[t12].[Description2] AS [Description],
[t12].[Host] AS [DeviceName],
[t12].[NET_OUID],
[t12].[DisplayName] AS [Net_OU],
[t12].[Enclave]
FROM (
SELECT
[t1].[DiscoveryEnabled] AS [value],
[t1].[IsConnected] AS [value2],
[t0].[Interface],
[t0].[Description],
[t2].[Duplex] AS [value3],
[t0].[IsEnabled] AS [value4],
[t3].[Host] AS [value5],
[t6].[Address] AS [value6],
[t3].[MAC] AS [value7],
[t3].[MACadded] AS [value8],
[t2].[PortFast] AS [value9],
[t2].[PortSecurity] AS [value10],
[t4].[Host] AS [value11],
[t0].[SNMPlink] AS [value12],
[t2].[Speed] AS [value13],
[t2].[InterfaceStatus] AS [value14],
[t8].[InterfaceType],
[t0].[IsUserPort] AS [value15],
[t2].[VLAN] AS [value16],
[t9].[Code] AS [value17],
[t9].[Description] AS [Description2],
[t7].[Host], [t7].[NET_OUID],
[t10].[DisplayName],
[t11].[Enclave],
[t7].[Decommissioned]
FROM [dbo].[IDB_Interface] AS [t0]
LEFT OUTER JOIN [dbo].[IDB_InterfaceLayer2] AS [t1] ON [t0].[IDB_Interface_ID] = [t1].[IDB_Interface_ID]
LEFT OUTER JOIN [dbo].[IDB_LANinterface] AS [t2] ON [t1].[IDB_InterfaceLayer2_ID] = [t2].[IDB_InterfaceLayer2_ID]
LEFT OUTER JOIN [dbo].[IDB_Host] AS [t3] ON [t2].[IDB_LANinterface_ID] = [t3].[IDB_LANinterface_ID]
LEFT OUTER JOIN [dbo].[IDB_Infrastructure] AS [t4] ON [t0].[IDB_Interface_ID] = [t4].[IDB_Interface_ID]
LEFT OUTER JOIN [dbo].[IDB_AddressMapIPv4] AS [t5] ON [t3].[IDB_AddressMapIPv4_ID] = ([t5].[IDB_AddressMapIPv4_ID])
LEFT OUTER JOIN [dbo].[IDB_AddressIPv4] AS [t6] ON [t5].[IDB_AddressIPv4_ID] = [t6].[IDB_AddressIPv4_ID]
INNER JOIN [dbo].[ART_Asset] AS [t7] ON [t7].[ART_Asset_ID] = [t0].[ART_Asset_ID]
LEFT OUTER JOIN [dbo].[NSD_InterfaceType] AS [t8] ON [t8].[NSD_InterfaceTypeID] = [t0].[NSD_InterfaceTypeID]
INNER JOIN [dbo].[NSD_InterfaceCode] AS [t9] ON [t9].[NSD_InterfaceCodeID] = [t0].[NSD_InterfaceCodeID]
INNER JOIN [dbo].[NET_OU] AS [t10] ON [t10].[NET_OUID] = [t7].[NET_OUID]
INNER JOIN [dbo].[NET_Enclave] AS [t11] ON [t11].[NET_EnclaveID] = [t10].[NET_EnclaveID]
) AS [t12]
WHERE ([t12].[Enclave] = 'USMC') AND (NOT ([t12].[Decommissioned] = 1))
LINQ-TO-SQL Query:
return from t in db.IDB_Interfaces
join v in db.IDB_InterfaceLayer3s on t.IDB_Interface_ID equals v.IDB_Interface_ID
join u in db.ART_Assets on t.ART_Asset_ID equals u.ART_Asset_ID
join c in db.NET_OUs on u.NET_OUID equals c.NET_OUID
join w in
(from d in db.IDB_InterfaceIPv4s
select new { d.IDB_InterfaceIPv4_ID, d.IDB_InterfaceLayer3_ID, d.IDB_AddressMapIPv4_ID, d.IDB_AddressMapIPv4.IDB_AddressIPv4.Address })
on v.IDB_InterfaceLayer3_ID equals w.IDB_InterfaceLayer3_ID
join h in db.NET_Enclaves on c.NET_EnclaveID equals h.NET_EnclaveID into enclaveLeftJoin
from i in enclaveLeftJoin.DefaultIfEmpty()
join m in
(from z in db.IDB_StandbyIPv4s
select new
{
z.IDB_InterfaceIPv4_ID,
z.IDB_AddressMapIPv4_ID,
z.IDB_AddressMapIPv4.IDB_AddressIPv4.Address,
z.Preempt,
z.Priority
})
on w.IDB_InterfaceIPv4_ID equals m.IDB_InterfaceIPv4_ID into standbyLeftJoin
from k in standbyLeftJoin.DefaultIfEmpty()
where t.ART_Asset.Decommissioned == false
select new NetIDBGridDataResults
{
DeviceName = u.Host,
Host = u.Host,
Interface = t.Interface,
IPAddress = w.Address,
ACLIn = v.InboundACL,
ACLOut = v.OutboundACL,
VirtualAddress = k.Address,
VirtualPriority = k.Priority,
VirtualPreempt = k.Preempt,
InterfaceDescription = t.Description,
Enclave = i.Enclave
};
As a rule (and this is very general), you want an index on:
JOIN fields (both sides)
Common WHERE filter fields
Possibly fields you aggregate
For this query, start with checking your JOIN criteria. Any one of those missing will force a table scan which is a big hit.
Looking at the execution plan of the query it seems like the outer joins are killing the query.
This query only returns 350k results, but it takes almost 30 seconds to complete. I don't know
much about DB's, but I don't think this is good? Perhaps I'm wrong?
A man has got to do waht a mana has got to do.
The joins may kill you, but when you need them YOU NEED THEM. Some tasks take long.
Make sure you ahve all indices you need.
Make sure your sql server is not a sad joke hardware wise.
All you can do.
I woudl bet someone has no clue about SQL and needs to be enlighted to the power of indices.

Nhibernate join filtering

I have a question about joins in NHIBERNATE. We had an issue with our sql query that was generated but nhibernate. Our db developer optimized the raw sql so it works as we need, but we need to change the nhibernate code to make generated sql look like optimized.
the part of the original part of the query is:
FROM PERSON_VISIT this_
inner join PERSON_Basic per2_
on this_.PERSON_ID = per2_.PERSON_ID
left outer join PERSONC_QUESTIONS perint10_
on per2_.PERSON_ID = perint10_.PERSON_ID
left outer join TELEPHONE_QUESTIONS intaudit13_
on perint10_.PP_QUESTIONS_ID = intaudit13_.PP_QUESTIONS_ID
inner join C_QUESTIONS intdef14_
on perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and perint10_.QUESTIONS_CODE = intdef14_.QUESTIONS_CODE
and perint10_.QUESTION_ID = intdef14_.QUESTION_ID
The optimized one is :
FROM PERSON_VISIT this_
inner join PERSON_Basic per2_
on this_.PERSON_ID = per2_.PERSON_ID
left outer join PERSONC_QUESTIONS perint10_
on per2_.PERSON_ID = perint10_.PERSON_ID
left outer join TELEPHONE_QUESTIONS intaudit13_
on perint10_.PP_QUESTIONS_ID = intaudit13_.PP_QUESTIONS_ID
left outer join C_QUESTIONS intdef14_
on perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and perint10_.QUESTIONS_CODE = intdef14_.QUESTIONS_CODE
and perint10_.QUESTION_ID = intdef14_.QUESTION_ID
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
To change query from inner join to left outer join is easy, i changed only one line of code:
.CreateAlias("PersonInt.QuestionEntity", "IntDef", JoinType.LeftOuterJoin)
But how I can add
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
using nhibernate code?
There is an option to add reference from PERSON_VISIT definition to C_QUESTIONS, but the problem is that
PERSON_VISIT is used everywhere and I don't want this change to possibly break other queries, I just wnat to add only one line of code to add, how I can do that? Is there any way to have access to the raw join to change it? Or some other way to add this
and intdef14_.DISCIPLINE_CODE = this_.DISCIPLINE_CODE
To the query?
I know that somebody will say that we can add a restriction to the query through criteria.Add, but it is not an option cause db developer optimized our query taking this restriction from WHERE clause to the join.
How I can do that quickly without changing the models definitions? Just changing only this one query without changing the whole model?
It is possible using HQL and the Criteria API's.
This question gives you the answer: Adding conditionals to outer joins with nhibernate
Something like this may solve your issue.
.CreateAlias("PersonInt.QuestionEntity", "IntDef", JoinType.LeftOuterJoin,
Restrictions.EqProperty("DISCIPLINE_CODE", "IntDef.DISCIPLINE_CODE"))
Thanks for answers. We use 2.0 version of NHibernate in our project so we didn't have a chance to use new methods of .CreateAlias with restrictions.
I have fixed an issue using Interceptors:
public class SqlInterceptor : EmptyInterceptor, IInterceptor
{
SqlString IInterceptor.OnPrepareStatement(SqlString sql)
{
//manipulating with the sql
return sql;
}
}
than
var factory = Session.SessionFactory;
var session = factory.OpenSession(new SqlInterceptor());
And use my query without a change.

spring mvc hibernate performance issues

We are working on a spring mvc project with hibernate.
When we execute the following code:
try {
HibernateTemplate ht = new HibernateTemplate(sf);
List<Route> r = ht.findByNamedParam("select r from Route r inner join r.carPoolers as carPooler where (( r.owner.id = :userid ) or ( carPooler.user.id = :userid )) AND r.id =:routeID", new String[]{"userid", "routeID"} , new Object[]{ u.getId() , id});
if (r.size() == 1) {
return r.get(0);
} else {
return null;
}
} catch (DataAccessException ex) {
LogFactory.getLog(RouteRepository.class).fatal(ex);
return null;
}
this is the result:
SELECT ROUTE0_.ID AS ID4_, ROUTE0_.ARRIVALTIME AS ARRIVALT2_4_,
ROUTE0_.CAR_ID AS CAR13_4_, ROUTE0_.DATE AS DATE4_,
ROUTE0_.DAYOFWEEK AS DAYOFWEEK4_, ROUTE0_.DEPARTURETIME AS
DEPARTUR5_4_, ROUTE0_.ENDDATE AS ENDDATE4_, ROUTE0_.MESSAGEID
AS MESSAGEID4_, ROUTE0_.OPENSEATS AS OPENSEATS4_,
ROUTE0_.OWNER_ID AS OWNER14_4_, ROUTE0_.ROUTECACHE_ID AS
ROUTECACHE11_4_, ROUTE0_.ROUTEOPTIMIZED AS ROUTEOPT9_4_,
ROUTE0_.START_ID AS START12_4_, ROUTE0_.STOP_ID AS STOP10_4_
FROM ROUTE ROUTE0_ INNER JOIN CARPOOLER CARPOOLERS1_ ON
ROUTE0_.ID=CARPOOLERS1_.ROUTEID
WHERE (route0_.owner_id=? or carpoolers1_.user_id=?) and route0_.id=?
SELECT CAR0_.ID AS ID5_3_, CAR0_.BRAND_ID AS BRAND8_5_3_, CAR0_.CARNAME
AS CARNAME5_3_, CAR0_.CARTYPE AS CARTYPE5_3_, CAR0_.IMAGEURL AS
IMAGEURL5_3_, CAR0_.PRICEKM AS PRICEKM5_3_, CAR0_.SEATS AS
SEATS5_3_, CAR0_.USER_ID AS USER7_5_3_, BRAND1_.ID AS ID6_0_,
BRAND1_.BRANDNAME AS BRANDNAME6_0_, USER2_.ID AS ID0_1_,
USER2_.EMAIL AS EMAIL0_1_, USER2_.FACEBOOKID AS FACEBOOKID0_1_,
USER2_.FIRSTNAME AS FIRSTNAME0_1_, USER2_.GENDER AS GENDER0_1_,
USER2_.IMAGEURL AS IMAGEURL0_1_, USER2_.LANGUAGE_ID AS
LANGUAGE12_0_1_, USER2_.LASTNAME AS LASTNAME0_1_,
USER2_.MOBILEPHONE AS MOBILEPH8_0_1_, USER2_.PASSWORD AS
PASSWORD0_1_, USER2_.SMOKER AS SMOKER0_1_, USER2_.TELEPHONE AS
TELEPHONE0_1_, LANGUAGE3_.ID AS ID9_2_, LANGUAGE3_.LANGUAGE AS
LANGUAGE9_2_, LANGUAGE3_.LANGUAGECODE AS LANGUAGE3_9_2_
FROM CAR CAR0_ LEFT OUTER JOIN BRAND BRAND1_ ON
CAR0_.BRAND_ID=BRAND1_.ID LEFT OUTER JOIN USER USER2_ ON
CAR0_.USER_ID=USER2_.ID LEFT OUTER JOIN LANGUAGE LANGUAGE3_ ON
USER2_.LANGUAGE_ID=LANGUAGE3_.ID
WHERE car0_.id=?
SELECT USER0_.ID AS ID0_1_, USER0_.EMAIL AS EMAIL0_1_,
USER0_.FACEBOOKID AS FACEBOOKID0_1_, USER0_.FIRSTNAME AS
FIRSTNAME0_1_, USER0_.GENDER AS GENDER0_1_, USER0_.IMAGEURL AS
IMAGEURL0_1_, USER0_.LANGUAGE_ID AS LANGUAGE12_0_1_,
USER0_.LASTNAME AS LASTNAME0_1_, USER0_.MOBILEPHONE AS
MOBILEPH8_0_1_, USER0_.PASSWORD AS PASSWORD0_1_, USER0_.SMOKER
AS SMOKER0_1_, USER0_.TELEPHONE AS TELEPHONE0_1_, LANGUAGE1_.ID
AS ID9_0_, LANGUAGE1_.LANGUAGE AS LANGUAGE9_0_,
LANGUAGE1_.LANGUAGECODE AS LANGUAGE3_9_0_
FROM USER USER0_ LEFT OUTER JOIN LANGUAGE LANGUAGE1_ ON
USER0_.LANGUAGE_ID=LANGUAGE1_.ID
WHERE user0_.id=?
SELECT ROUTECACHE0_.ID AS ID7_2_, ROUTECACHE0_.AANTALM AS AANTALM7_2_,
ROUTECACHE0_.AANTALMIN AS AANTALMIN7_2_, ROUTECACHE0_.ACTIVE AS
ACTIVE7_2_, ROUTECACHE0_.JSON AS JSON7_2_,
ROUTECACHE0_.LOCATIONS AS LOCATIONS7_2_,
ROUTECACHE0_.LOCATIONSOPTIMIZED AS LOCATION7_7_2_,
ROUTECACHE0_.ROUTEOPTIMIZED AS ROUTEOPT8_7_2_,
ROUTECACHE0_.START_ID AS START10_7_2_, ROUTECACHE0_.STOP_ID AS
STOP9_7_2_, LOCATION1_.ID AS ID2_0_, LOCATION1_.LANG AS
LANG2_0_, LOCATION1_.LAT AS LAT2_0_, LOCATION1_.NUMBER AS
NUMBER2_0_, LOCATION1_.STREET AS STREET2_0_, LOCATION1_.ZIPCODE
AS ZIPCODE2_0_, LOCATION2_.ID AS ID2_1_, LOCATION2_.LANG AS
LANG2_1_, LOCATION2_.LAT AS LAT2_1_, LOCATION2_.NUMBER AS
NUMBER2_1_, LOCATION2_.STREET AS STREET2_1_, LOCATION2_.ZIPCODE
AS ZIPCODE2_1_
FROM ROUTECACHE ROUTECACHE0_ LEFT OUTER JOIN LOCATION LOCATION1_ ON
ROUTECACHE0_.START_ID=LOCATION1_.ID LEFT OUTER JOIN LOCATION
LOCATION2_ ON ROUTECACHE0_.STOP_ID=LOCATION2_.ID
WHERE routecache0_.id=?
SELECT ROUTECACHE0_.ROUTECACHESPUNTENTUSSEN_ID AS ROUTECAC1_1_,
ROUTECACHE0_.ROUTECACHETUSSENPUNTEN_ID AS ROUTECAC2_1_,
LOCATION1_.ID AS ID2_0_, LOCATION1_.LANG AS LANG2_0_,
LOCATION1_.LAT AS LAT2_0_, LOCATION1_.NUMBER AS NUMBER2_0_,
LOCATION1_.STREET AS STREET2_0_, LOCATION1_.ZIPCODE AS
ZIPCODE2_0_
FROM ROUTECACHE_LOCATION_PUNTEN ROUTECACHE0_ LEFT OUTER JOIN LOCATION
LOCATION1_ ON
ROUTECACHE0_.ROUTECACHETUSSENPUNTEN_ID=LOCATION1_.ID
WHERE routecache0_.routecachesPuntenTussen_id=?
SELECT CARPOOLERS0_.ROUTEID AS ROUTEID5_, CARPOOLERS0_.ID AS ID5_,
CARPOOLERS0_.ID AS ID3_4_, CARPOOLERS0_.APPROVED AS
APPROVED3_4_, CARPOOLERS0_.ONETIME AS ONETIME3_4_,
CARPOOLERS0_.ROUTEID AS ROUTEID3_4_, CARPOOLERS0_.START_ID AS
START5_3_4_, CARPOOLERS0_.STOP_ID AS STOP7_3_4_,
CARPOOLERS0_.USER_ID AS USER6_3_4_, LOCATION1_.ID AS ID2_0_,
LOCATION1_.LANG AS LANG2_0_, LOCATION1_.LAT AS LAT2_0_,
LOCATION1_.NUMBER AS NUMBER2_0_, LOCATION1_.STREET AS
STREET2_0_, LOCATION1_.ZIPCODE AS ZIPCODE2_0_, LOCATION2_.ID AS
ID2_1_, LOCATION2_.LANG AS LANG2_1_, LOCATION2_.LAT AS LAT2_1_,
LOCATION2_.NUMBER AS NUMBER2_1_, LOCATION2_.STREET AS
STREET2_1_, LOCATION2_.ZIPCODE AS ZIPCODE2_1_, USER3_.ID AS
ID0_2_, USER3_.EMAIL AS EMAIL0_2_, USER3_.FACEBOOKID AS
FACEBOOKID0_2_, USER3_.FIRSTNAME AS FIRSTNAME0_2_,
USER3_.GENDER AS GENDER0_2_, USER3_.IMAGEURL AS IMAGEURL0_2_,
USER3_.LANGUAGE_ID AS LANGUAGE12_0_2_, USER3_.LASTNAME AS
LASTNAME0_2_, USER3_.MOBILEPHONE AS MOBILEPH8_0_2_,
USER3_.PASSWORD AS PASSWORD0_2_, USER3_.SMOKER AS SMOKER0_2_,
USER3_.TELEPHONE AS TELEPHONE0_2_, LANGUAGE4_.ID AS ID9_3_,
LANGUAGE4_.LANGUAGE AS LANGUAGE9_3_, LANGUAGE4_.LANGUAGECODE AS
LANGUAGE3_9_3_
FROM CARPOOLER CARPOOLERS0_ LEFT OUTER JOIN LOCATION LOCATION1_ ON
CARPOOLERS0_.START_ID=LOCATION1_.ID LEFT OUTER JOIN LOCATION
LOCATION2_ ON CARPOOLERS0_.STOP_ID=LOCATION2_.ID LEFT OUTER
JOIN USER USER3_ ON CARPOOLERS0_.USER_ID=USER3_.ID LEFT OUTER
JOIN LANGUAGE LANGUAGE4_ ON USER3_.LANGUAGE_ID=LANGUAGE4_.ID
WHERE carpoolers0_.RouteId=?
Problem:
This takes minimum 460ms.
We only need the first query for our results.
,
ty in advance
You probably have so many queries because some relationships are eager loaded. Note that by default all OneToOne and ManyToOne relationships are eager loaded. This means that if a route has a car, which has a user, which has a language, etc., Hibernate will load all these referenced entities each time it loads a route.
Make them lazy loaded instead, and tune your queries to fetch only the entities you need.
I guess returned object is passed to some automatic serializer (you use #ResponseBody, yes?) that tries to serialize the whole graph of accessible objects and therefore triggers lazy loading of related objects which you don't need.
If so, you can create a DTO that contains only necessary fields, populate it from the loaded entity and return that DTO instead of entity.
Alternative approach would be to configure serializer to make it serialize only necessary fields, but it can be more complex.
See this for how to get only 1 result: How do you do a limit query in HQL?.
Have you configured indexes on your tables?

Why does Linq to Nhibernate produce an outer join

I have an issue with Linq to Nhibernate producing queries with outer joins.
For example:
return Session.Linq<ClientContact>().Where(c => c.Client.Id = 13).ToList();
Produces a query similar to:
SELECT...
FROM mw_crafru.clientcontact this_,
mw_crafru.client client1_,
mw_crafru.relationshiptype relationsh4_
WHERE this_.clientid = client1_.clientid(+)
AND this_.relationshiptypeid = relationsh4_.relationshiptypeid
AND client1_.clientid = :p0;:p0 = 13
Notice the outer join this.clientid = client1.clientid(+). Boo!
To resolve the issue I went back to using Session.CreateCriteria.
return Session.CreateCriteria(typeof (ClientContact)).Add(Restrictions.Eq("Client.Id", clientId)).List<ClientContact>();
Produces the following query:
SELECT...
FROM mw_crafru.clientcontact this_,
mw_crafru.client client1_,
mw_crafru.relationshiptype relationsh4_
WHERE this_.clientid = client1_.clientid
AND this_.relationshiptypeid = relationsh4_.relationshiptypeid
AND client1_.clientid = :p0;:p0 = 13
Notice no outer join this.clientid = client1.clientid. Yay!
Anyone know why this is happening?
With SQL Server at least, a many-to-one mapping with not-null="true", or Not.Nullable() using Fluent NH, causes Get operations to use an inner join instead of a left join. Try adding that to your mapping for Client in ClientContact.

Query performance fluctuation

i'm running queries from NHibernate and have my profiler set up to trace any slow queries, there are a few which seem to take 10+ seconds in my profiler mainly:
exec sp_executesql N'SELECT top 50 this_.Debiteur_ID as Debiteur1_44_6_, this_.Debiteurnaam as Debiteur2_44_6_, this_.Debiteurnummer as Debiteur3_44_6_, this_.IsBedrijf_NeeJa as
IsBedrijf4_44_6_, this_.Bedrijfsnaam as Bedrijfs5_44_6_, this_.Achternaam as Achternaam44_6_, this_.Tussenvoegsel as Tussenvo7_44_6_, this_.Voorletters as Voorlett8_44_6_,
this_.Geboortedatum as Geboorte9_44_6_, this_.Titel_ID as Titel10_44_6_, this_.ManVrouw as ManVrouw44_6_, this_.Entiteit_ID as Entiteit12_44_6_, this_.Rechtsvorm_ID as Rechtsvorm13_44_6_,
this_.Account_ID as Account14_44_6_, this_.Vestiging_Postcode as Vestiging15_44_6_, this_.Vestiging_Adres as Vestiging16_44_6_, this_.Vestiging_Plaats as Vestiging17_44_6_,
this_.Vestiging_Huisnummer as Vestiging18_44_6_, this_.Vestiging_Land_ID as Vestiging19_44_6_, this_.Correspondentie_Postcode as Corresp20_44_6_, this_.Correspondentie_Adres as
Corresp21_44_6_, this_.Correspondentie_Plaats as Corresp22_44_6_, this_.Correspondentie_Huisnummer as Corresp23_44_6_, this_.Correspondentie_Land_ID as Corresp24_44_6_, this_.Telefoonnummer as Telefoo25_44_6_, this_.Email as Email44_6_, this_.Mobiel as Mobiel44_6_, title3_.Titel_ID as Titel1_65_0_, title3_.Omschrijving as Omschrij2_65_0_, gender4_.Geslacht_ID as Geslacht1_30_1_, gender4_.Omschrijving as Omschrij2_30_1_, typeofcomp5_.Rechtsvorm_ID as Rechtsvorm1_8_2_, typeofcomp5_.Omschrijving as Omschrij2_8_2_, country6_.Land_ID as Land1_7_3_, country6_.Omschrijving as Omschrij2_7_3_, country6_.ISO as ISO7_3_, country6_.ISO_3166_a3 as ISO4_7_3_, country7_.Land_ID as Land1_7_4_, country7_.Omschrijving as Omschrij2_7_4_, country7_.ISO as ISO7_4_, country7_.ISO_3166_a3 as ISO4_7_4_, debtorreac1_.Debiteur_ID as Debiteur1_3_5_, debtorreac1_.DateOfOldestReaction as DateOfOl2_3_5_, debtorreac1_.TotalAmountOfReactions as TotalAmo3_3_5_, debtorreac1_.AmountOfResolvedReactions as AmountOf4_3_5_, debtorreac1_.AmountOfUnresolvedReactions as AmountOf5_3_5_, debtorreac1_.TotalOpenAmount as TotalOpe6_3_5_, debtorreac1_.UnresolvedOpenAmount as Unresolv7_3_5_, debtorreac1_.ResolvedOpenAmount as Resolved8_3_5_ FROM tbl_Debiteur this_ left outer join tbl_Titel title3_ on this_.Titel_ID=title3_.Titel_ID left outer join tbl_Geslacht gender4_ on this_.ManVrouw=gender4_.Geslacht_ID left outer join tbl_Rechtsvorm typeofcomp5_ on this_.Rechtsvorm_ID=typeofcomp5_.Rechtsvorm_ID left outer join tbl_Land country6_ on this_.Vestiging_Land_ID=country6_.Land_ID left outer join tbl_Land country7_ on this_.Correspondentie_Land_ID=country7_.Land_ID left outer join vw_DebtorReactionDetails debtorreac1_ on this_.Debiteur_ID=debtorreac1_.Debiteur_ID WHERE this_.Entiteit_ID = #p0 and debtorreac1_.AmountOfUnresolvedReactions > #p1 ORDER BY this_.Debiteur_ID asc',N'#p0 int,#p1 int',#p0=1104,#p1=0
When i run the exact same query i just pasted here like this so including the parameters and everything the query takes less then a second.
I have no idea why this is happening but performance as it is right now simply isn't going to work out.
Greetings.
Been a while since i visited this topic, we tweaked the query some, added some more indexes but more importantly now run on a more powerfull server.
This all said i believe the problem i was running into was one of Parameter sniffing:
http://www.simple-talk.com/sql/t-sql-programming/parameter-sniffing/
The issue(s) for now atleast are resolved.
Are you sure that the query itself is the culprit?
I'm pretty sure that its not the execution of the query that is slow but the process of hydrating the according mapped entities and especially considering collections and/or many-to-one associations and their collection when you have disabled lazy loading.
first check your mappings if you have set eager fetching,
try setting
<property name="max_fetch_depth">1</property>
in your NH config just to limit automatic eager fetching (remember to remove/change the value afterwards)