简体   繁体   中英

Very slow update with nHibernate with a SQLite database

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();
}

如果您唯一要更新的是父母或母亲,则可以在Patient的映射文件中使用dynamic-update="true"

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM