什么会影响nhibernate批量插入性能?

时间:2012-12-19 16:12:09

标签: c# nhibernate

我在基于c#和Fluent NHibernate构建的项目中有各种大型数据修改操作。 DB是sqlite(在磁盘上而不是在内存中,因为我对性能感兴趣)

我想检查这些的性能,所以我创建了一些测试来提供大量数据并让流程做他们的事情。其中2个过程的结果让我很困惑。

第一个是一个相当简单的例子,即在XML文件中提供数据进行一些轻量处理并导入它。 XML包含大约172,000行,并且该过程总共需要大约60秒才能运行,实际插入大约需要40秒。

在下一个过程中,我对同一组数据进行一些处理。所以我在一个表中有一个大约172,000行的数据库。然后,该过程将处理此数据,执行一些较重的处理并生成一大堆数据库更新(插入和更新到同一个表)。 总的来说,这会导致插入大约50,000行并更新80,000行。 在这种情况下,处理大约需要30秒,这很好,但保存对DB的更改需要30分钟!并且它在使用sqlite'磁盘或i / o错误'

完成之前崩溃

所以问题是:为什么第二个进程中的插入/更新速度要慢得多?它们使用相同的连接在同一个数据库的同一个表上工作。在这两种情况下,都使用IStatelessSession,ado.batch_size设置为1000.

在这两种情况下,代码看起来像这样执行更新:

BulkDataInsert((IStatelessSession session) =>
{
    foreach (Transaction t in transToInsert) { session.Insert(t); }
    foreach (Transaction t in transToUpdate) { session.Update(t); }
});

(虽然第一个进程没有'transToUpdate'行,因为它只是插入 - 删除更新行只是进行插入仍然需要大约10分钟。) transTo *变量是List,包含要更新/插入的对象。

BulkDataInsert创建会话并处理数据库事务。

2 个答案:

答案 0 :(得分:0)

我不明白你的第二个过程。但是,有些事情需要考虑:

  1. 桌面上是否有任何群集或非群集索引?
  2. 您有多少个磁盘驱动器?
  3. 第二次测试中有多少线程写入数据库?
  4. 您似乎遇到了IO瓶颈,可以通过拥有更多磁盘,更多线程,索引等来解决这些问题。

    所以,假设很多事情,这就是我“想到”的事情:

    1. 在第一个测试中,您的表可能没有索引,并且由于您只是插入数据,因此它是单个线程中的顺序插入,这可能非常快 - 特别是如果您正在写入一个磁盘。
    2. 现在,在第二个测试中,您正在读取数据然后更新数据。您的SQL实例必须找到它需要更新的记录。如果您没有任何索引,则此“查找”操作基本上是一个表扫描,这将针对这80,000行更新中的每一个进行。这将使你的应用程序真的很慢。
    3. 您可能做的最简单的事情是在表上添加一个唯一键的聚簇索引,最好的选择是使用您在where子句中使用的列来“更新”这些行。

      希望这有帮助。

      免责声明:我做了很多假设

答案 1 :(得分:0)

问题是由于我的测试设置。 对于基于nhibernate的项目来说非常常见,我一直在使用内存中的sqlite数据库进行单元测试。这些工作很好,但一个缺点是,如果你关闭会话,它会破坏数据库。 因此,我的工作单元实现包含一个'PreserveSession'属性,以保持会话处于活动状态,并在需要时创建新的事务。

我的新性能测试使用的是磁盘数据库,但它们仍然使用公共代码来设置测试数据库,因此将PreserveSession设置为true。

似乎有几个会话都打开了(即使它们没有做任何事情)一段时间后开始出现问题,包括性能下降和磁盘IO错误。

我在PreserveSession设置为false的情况下重新进行了第二次测试,并且我立刻从30分钟到2分钟不到。这是我期望的更多。

相关问题