【问题标题】:what can affect nhibernate bulk insert performance?什么会影响 nhibernate 批量插入性能?
【发布时间】:2012-12-19 16:12:08
【问题描述】:

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

我想检查这些性能,所以我创建了一些测试来输入大量数据并让流程完成它们的工作。其中两个过程的结果让我很困惑。

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

在接下来的过程中,我对同一组数据进行了一些处理。所以我有一个数据库,一张表中有大约 172,000 行。然后该过程处理这些数据,进行一些更繁重的处理并生成一大堆数据库更新(插入和更新到同一个表)。 总的来说,这会导致插入大约 50,000 行并更新 80,000 行。 在这种情况下,处理大约需要 30 秒,这很好,但是将更改保存到数据库需要 30 多分钟!它在完成之前崩溃并出现 sqlite 'disk or i/o error'

所以问题是:为什么第二个过程中的插入/更新要慢得多?他们使用相同的连接处理同一个数据库的同一张表。在这两种情况下,都使用 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* 变量是列表,其中包含要更新/插入的对象。

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

【问题讨论】:

    标签: c# nhibernate


    【解决方案1】:

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

    1. 表上是否有任何聚集或非聚集索引?
    2. 您有多少个磁盘驱动器?
    3. 第二个测试中有多少线程正在写入数据库?

    您似乎遇到了 IO 瓶颈,可以通过拥有更多磁盘、更多线程、索引等来解决。

    所以,假设有很多事情,这就是我“认为”正在发生的事情:

    1. 在第一次测试中,您的表可能没有索引,并且由于您只是插入数据,因此它是在单个线程中的顺序插入,速度可能非常快 - 特别是当您正在写入一个磁盘时。
    2. 现在,在第二个测试中,您正在读取数据,然后更新数据。您的 SQL 实例必须找到它需要更新的记录。如果您没有任何索引,则此“查找”操作基本上是表扫描,这将针对这 80,000 行更新中的每一个进行。这将使您的应用程序非常缓慢。

    您可能会做的最简单的事情是在表上添加一个聚集索引以获得唯一键,最好的选择是使用您在 where 子句中使用的列来“更新”这些行。

    希望这会有所帮助。

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

    【讨论】:

    • 1.有2个指标。主键(long 或 int,因为这是 SQLite,它对待它们相同)和另一个非聚集在日期列上。 2.只有一个驱动器。 SQLite 是基于单个文件的数据库。 3.只有一个线程。在第一次和第二次测试中是同一张表。如果我只保存插入并忽略更新,我也会减慢速度,所以我认为这与表本身没有任何关系。更新都将按 ID 进行,这是主键和聚集索引,所以应该尽可能快。
    【解决方案2】:

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

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

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

    我在 PreserveSession 设置为 false 的情况下重新运行了第二个测试,然后我立即从 30 多分钟减少到 2 分钟以下。这是我所期望的更多。

    【讨论】:

      猜你喜欢
      • 2012-01-30
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-11
      • 2019-12-07
      相关资源
      最近更新 更多