Reputation: 4269
I'm using nHibernate with one session per method. I'm using Castle Dynamic Proxy to open a session and a transaction before executing the method and I commit the transaction and close the session right after the execution of this method.
I'm using a SQLite database and if set cascade to SaveUpdate or None doesn't change anything. nHIbernate is configured with Fluent nHibernate with the default configuration.
When I flush the session, it takes more than 2 seconds.
public void AddNewChild(LightPatientDto patient, LightPatientDto child)
{
var ePatient = this.Session.Load<Patient>(patient.Id);
var eChild = this.Session.Load<Patient>(child.Id);
switch (ePatient.Gender)
{
case Gender.Male:
eChild.Father = ePatient;
break;
case Gender.Female:
eChild.Mother = ePatient;
break;
default:
Assert.FailOnEnumeration(eChild.Gender);
break;
}
this.Session.Update(eChild);
this.Session.Flush(); // <== takes more than 2 seconds
}
NHibernate profiler gives me this SQL is executed in 2008 ms. When I copy paste this SQL using a SQLite administration tool, it's executed in 90 ms.
UPDATE Patient
SET BirthDate = '1964-05-06T00:00:00.00' /* @p0 */,
Fee = 0 /* @p1 */,
Height = 0 /* @p2 */,
InscriptionDate = '2007-05-21T00:00:00.00' /* @p3 */,
PlaceOfBirth = 'xxxxxx' /* @p4 */,
PrivateMail = '' /* @p5 */,
PrivateMobile = NULL /* @p6 */,
PrivatePhone = '0496/xx.xx.xx' /* @p7 */,
Reason = 'diabète' /* @p8 */,
Father_id = 2 /* @p9 */,
Insurance_id = 1 /* @p10 */,
Mother_id = NULL /* @p11 */,
Practice_id = 1 /* @p12 */,
Profession_id = NULL /* @p13 */,
Reputation_id = 1 /* @p14 */
WHERE Person_id = 3 /* @p15 */
How can I optimise the execution time?
EDIT 1
As @csanchez suggested, I've succeeded to add Dynamic Update for my entity. Now when I'm looking the SQL into NH Profiler, I've got this:
UPDATE Patient
SET Father_id = 2 /* @p0 */
WHERE Person_id = 21 /* @p1 */
Which is a lot optimised! But, the execution time is ... 1852 ms o_O
In the debugger, I see that it is committing the transaction that takes time... And I have no clue why it is so slow...
EDIT 2
Each patient has medical pictures that are stored into a table as bytes arrays. Here's the SQL for the table creation (done by Fluent nHibernate)
CREATE TABLE Picture (
Id integer PRIMARY KEY AUTOINCREMENT,
Bitmap blob,
Creation datetime,
LastUpdate datetime,
Notes text,
IsImported bool,
Tag_id bigint,
Patient_id bigint,
ThumbnailBitmap blob,
/* Foreign keys */
FOREIGN KEY (Patient_id)
REFERENCES Patient(),
FOREIGN KEY (Tag_id)
REFERENCES "Tag"()
);
If I drop the data with DELETE Picture
and restart the application, the update is light speed fast.
It seems like nHibernate try to be smart and does something that slows down everything. But event if I execute a pure SQL query with this code, the update still takes more than one second:
using (var tx = this.Session.BeginTransaction())
{
var sql = "UPDATE Patient SET Father_id = 2 WHERE Person_id = 21";
var query = this.Session.CreateSQLQuery(sql);
query.ExecuteUpdate();
tx.Commit();
}
Upvotes: 2
Views: 1296
Reputation: 121
If the only thing you update is the Parent or the Mother you could use dynamic-update="true"
, in the mapping file of the Patient.
Upvotes: 1
Reputation: 6911
You should not flush your session every time you make a change to data. You should let NHibernate buffer updates and flush bulk changes. Otherwise, they would have made flush implicit operation and not have you worry about it.
Upvotes: 0
Reputation: 34698
Is this performance hit just with the first commit to the DB. SQLite may have some spin-up time.
You say "session per method" yet it looks like you're using a module-level session variable. The more that is done with a Session instance, the slower it will become due to caching. If this is going to be more of a batch operation, consider the StatelessSession.
Also check the logging configuration for NHibernate + Log4Net. The more detailed the logging, the slower NH will respond.
Upvotes: 0