我的NHibernate / SQLite项目中的提交非常慢

时间:2010-03-26 20:54:31

标签: nhibernate sqlite fluent-nhibernate

我刚刚开始在我的Fluent NHibernate / SQLite项目上进行一些真实的性能测试,并且在我提交数据库时遇到了一些严重的延迟。严肃地说,我的意思是花20到30秒来提交30 K的数据!

随着数据库的增长,这种延迟似乎变得更糟。当SQLite数据库文件为空时,提交几乎立即发生,但当它增长到10兆时,我看到这些巨大的延迟。

数据库有16个表,每个表平均10列。

一个可能的问题是我存储了十几个IList<float>成员,但它们通常只有200个元素。但这是Fluent NHibernate自动化的最新成员,它将每个浮点数存储在一个表行中,所以这可能是一个潜在的问题。

有关如何跟踪此问题的任何建议?我怀疑SQLite是罪魁祸首,但也许它是NHibernate?

我对剖析仪没有任何经验,但我想考虑一个。我知道NHibernate Profiler - 有关与SQLite配合使用的分析器的任何建议吗?

修改

更多的测试表明,数据库的大小不会导致速度减慢 - 这取决于自我启动程序以来我完成了多少次保存。第一次保存的提交时间约为300毫秒,第50次保存则超过1000毫秒。

我一直打开一个Session - 也许我需要一些明确的Flush逻辑?

另外,我下载了NHibernate Profiler。它为我的IList成员提供了关于“大量个人写入”的警报。警报描述建议启用批处理,但据我所知,SQLite不支持这一点。

还提到了Multiquery支持,所以我将继续阅读。

/修改

这是保存数据的方法 - 如果忽略所有错误处理和调试日志记录,它只是一个SaveOrUpdate调用和一个Commit。

    public static void SaveMeasurement(object measurement)
    {
        // Get the application's database session
        var session = GetSession();
        using (var transaction = session.BeginTransaction())
        {
            session.Save(measurement);
            transaction.Commit();
        }
    }

6 个答案:

答案 0 :(得分:4)

您的交易应该围绕整个操作,而不是每次保存。

您还可以从启用ado.net批处理中受益:     1000

答案 1 :(得分:3)

我认为使用session.evict()仅涵盖症状。你没有发布GetSession() - 方法,但上面的注释和session.clear()破坏你的延迟加载的注释使我猜你正在为整个应用程序使用一个会话。
这非常低效,并且会在运行的时间越长,从而减慢应用程序的速度。另一方面,创建一个新会话非常便宜,它将为您提供干净,快速的会话,只处理您想要的对象。
IMO你应该考虑声明式事务管理。我个人更喜欢Springs - TX-Management,但也有其他聪明的解决方案不是基于方法的,例如城堡的ActiveRecord

答案 2 :(得分:2)

您说您有一个测量对象列表,但您一次保存1个。如果所有保存都在1个事务中,那么这样就可以了,但是每个保存都包含在事务中。无论数据库有多大,这都会损害您的性能。

答案 3 :(得分:1)

您使用自动增量主键吗?这将导致NHibernate在每次插入后执行select以填充对象上的主键属性。我不确定它是如何为SQLite做的,但你的说法是,随着数据库增长指出问题变得更糟,这可能是根本原因。

您使用分析器的计划是最佳方案。 NHibernate Profiler非常出色,并且有一个试用期,允许您使用它来解决此问题。

答案 4 :(得分:1)

Nhibernate永远不会很快。

某些旧版本的nhibernate会主动关闭数据库的会话。这导致它打开/关闭sqlite数据库很多(这很慢)。我相信较新版本包含一个选项,可以让nhibernate会话保持更长时间。如果你正在使用内存数据库,它会导致一切都关闭后丢失。

Problem using SQLite :memory: with NHibernate

答案 5 :(得分:-1)

修改 在阅读了zoidbeck的回答后,我放弃了这种方法。看我对他的回答的评论。 的 /修改

经过一些谷歌搜索后,我发现了一些帖子,这些帖子暗示NHibernate缓存在某些情况下实际上可能会大大降低速度。显然,NH可以花更多的时间在缓存中查找,而不是实际的提交。

我尝试了一个session.Clear在每次Commit之后,但是这会导致延迟加载。

解决方案(目前)是致电:

session.Evict(measurement);

每次提交后,从缓存中删除测量值。现在,无论数据库有多大,我的提交大致需要大约相同的时间(大约800毫秒,30 K数据)。

根问题似乎是我的IList<float>成员,它们会生成数百个SQL插入内容。批处理可能会解决这个问题,但是,唉,只有SQL Server支持,而不是SQLite。

在某些时候,我将不得不优化它 - 可能将它们存储为BLOB。但那是另一天的问题。