在我的NHibernate/SQLite项目中,Commit非常慢

在我的NHibernate/SQLite项目中,Commit非常慢,nhibernate,sqlite,fluent-nhibernate,Nhibernate,Sqlite,Fluent Nhibernate,我刚刚开始对我的Fluent NHibernate/SQLite项目进行一些真实的性能测试,在提交数据库时遇到了一些严重的延迟。我说的认真,是指花20-30秒提交30K数据 随着数据库的增长,这种延迟似乎越来越严重。当SQLite DB文件为空时,提交几乎立即发生,但当它增长到10兆时,我看到了这些巨大的延迟 该数据库有16个表,平均每个表有10列 一个可能的问题是,我存储了十几个左右的IList成员,但它们通常只有200个元素长。但这是Fluent NHibernate automapping

我刚刚开始对我的Fluent NHibernate/SQLite项目进行一些真实的性能测试,在提交数据库时遇到了一些严重的延迟。我说的认真,是指花20-30秒提交30K数据

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

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

一个可能的问题是,我存储了十几个左右的
IList
成员,但它们通常只有200个元素长。但这是Fluent NHibernate automapping的最新添加,它将每个浮点存储在一个表行中,所以这可能是一个潜在的问题

有没有关于如何追踪的建议?我怀疑SQLite是罪魁祸首,但也许是NHibernate

我没有任何使用分析器的经验,但我正在考虑使用分析器。我知道-对于能够与SQLite很好地工作的分析器,有什么建议吗

编辑

更多的测试表明,导致减速的不是数据库的大小,而是我启动程序后进行了多少次保存。第一次保存的提交时间约为300毫秒,到第50次保存时将超过1000毫秒

我一直保持一个会话打开-也许我需要一些明确的刷新逻辑

此外,我还下载了NHibernate档案器。它让我对IList成员的“大量个人写作”有所警觉。警报描述建议启用批处理,但据我所知,SQLite不支持这一点

还提到了多查询支持,所以我将详细阅读

/Edit

下面是保存数据的方法—如果忽略所有错误处理和调试日志记录,它只是一个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();
        }
    }

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

您的事务应该围绕整个操作进行,而不是每次保存

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

是否使用自动递增主键?这将导致NHibernate在每次插入后执行选择,以填充对象上的主键属性。我不确定它是如何处理SQLite的,但您关于随着数据库的增长问题会变得更糟的说法指出,这可能是一个根本原因

您使用探查器的计划是最佳的行动方案。NHibernate探查器非常优秀,有一个试用期,可以让您使用它来解决此问题。

编辑 在阅读了zoidbeck的答案后,我放弃了这种方法。请看我对他的回答的评论。 /Edit

在谷歌搜索之后,我发现了一些帖子,暗示NHibernate缓存实际上可以在某些情况下大大降低速度。显然,NH在缓存中查找内容的时间比实际提交的时间要多

我试着做一个会话。每次提交后都会清除,但这打破了延迟加载

目前的解决方案是:

session.Evict(measurement);
每次提交后,将从缓存中删除度量。现在,无论数据库有多大,我的提交所用的时间大致相同(对于30K的数据,大约800ms)

根本问题似乎是my
IList
成员,它们生成数百个SQL插入。批处理可能会解决这个问题,但遗憾的是,只有SQL Server支持批处理,而SQLite不支持批处理


在某个时候,我必须对此进行优化——也许可以将它们存储为一个BLOB。但这是另一天的问题。

Nhibernate永远不会跑得快

一些旧版本的nhibernate会主动关闭与数据库的会话。这导致它经常打开/关闭sqlite数据库(这非常慢)。我相信新版本包括一个选项,可以让nhibernate会话保持更长的开放时间。如果您使用的是内存数据库,那么一旦关闭,就会导致所有内容丢失


我认为使用session.execute()只能解决问题。您尚未发布GetSession()-方法,但上面的注释以及session.clear()中断延迟加载的注释使我猜测您正在为整个应用程序使用一个会话。
这是非常低效的,运行时间越长,应用程序运行速度就会越慢。另一方面,创建一个新的会话非常便宜,它将为您提供一个干净、快速的会话,只处理您想要的对象。

在我看来,您应该考虑声明式事务管理。就我个人而言,我更喜欢-TX管理,但也有其他聪明的解决方案不是基于这种方法的,比如castle的

您是否正确使用事务?或者你有没有在添加新记录之前搜索现有记录的代码?@Kevin-我想有,但我刚刚发布了一个代码片段-如果你发现任何问题,请告诉我。当我填充一个空数据库时,我看到了延迟——没有其他逻辑寻找DUP。nhprof与SQLITE配合得很好谢谢你的建议。我将SaveOrUpdate更改为Save,但仍然会出现延迟。目前,我只保存了大约1000个度量对象来填充我的数据库——我提到的ILists是度量类的成员。但是我在保存度量值时使用DefaultCascade.All()约定使ILists保存-也许这是在隐式地执行SaveOrUpdate?@Tom我很抱歉。我不确定。对整个第2批使用一个事务处理。使用save添加一个新的,当您使用一个事务时,您根本不需要使用显式更新。所以,你们说我应该:1)执行单个“BeginTrans”