【问题标题】:Very slow update with nHibernate with a SQLite database使用 SQLite 数据库使用 nHibernate 更新非常慢
【发布时间】:2012-11-04 21:02:49
【问题描述】:

我正在使用 nHibernate,每种方法都有一个会话。我正在使用 Castle Dynamic Proxy 在执行该方法之前打开一个会话和一个事务,并在执行此方法后立即提交事务并关闭会话。

我正在使用 SQLite 数据库,如果将级联设置为 SaveUpdate 或 None 不会改变任何东西。 nHIbernate 使用 Fluent nHibernate 和默认配置进行配置。

当我刷新会话时,它需要超过 2 秒。

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 分析器告诉我这个 SQL 是在 2008 毫秒内执行的。当我使用 SQLite 管理工具复制粘贴此 SQL 时,它会在 90 毫秒内执行。

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 */

如何优化执行时间?

编辑 1

正如@csanchez 建议的那样,我已成功为我的实体添加动态更新。现在,当我在 NH Profiler 中查看 SQL 时,我得到了这个:

UPDATE Patient
SET    Father_id = 2 /* @p0 */
WHERE  Person_id = 21 /* @p1 */

优化了很多!但是,执行时间是... 1852 ms o_O

在调试器中,我看到它正在提交需要时间的事务......而且我不知道为什么它这么慢......

编辑 2

每位患者都有医学图片,这些图片以字节数组的形式存储在表格中。这是创建表的 SQL(由 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"()
);

如果我用DELETE Picture 删除数据并重新启动应用程序,更新速度很快。

nHibernate 似乎试图变得聪明,并做了一些减慢一切的事情。但是如果我用这段代码执行一个纯 SQL 查询,更新仍然需要一秒钟以上:

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

【问题讨论】:

    标签: c# nhibernate


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      这种性能是否仅在第一次提交到数据库时受到影响。 SQLite 可能有一些启动时间。

      您说“每个方法的会话”,但看起来您正在使用模块级会话变量。使用 Session 实例完成的越多,由于缓存,它会变得越慢。如果这将是更多的批处理操作,请考虑 StatelessSession。

      同时检查 NHibernate + Log4Net 的日志配置。日志记录越详细,NH 的响应速度就越慢。

      【讨论】:

      • nHibernate 仅记录从警告到致命的日志。正如我所说,动态代理打开会话,调用方法并最终关闭会话。每次调用该方法,这个简单的更新需要 2 秒。
      【解决方案3】:

      您不应该在每次更改数据时刷新会话。您应该让 NHibernate 缓冲更新并刷新批量更改。否则,他们会进行flush隐式操作,而您不必担心。

      【讨论】:

      • 如果我删除 Flush(),那么提交事务需要 2 秒
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      • 2021-12-19
      • 1970-01-01
      相关资源
      最近更新 更多