【问题标题】:How to diagnose slow NHibernate inserts?如何诊断缓慢的 NHibernate 插入?
【发布时间】:2012-06-08 04:11:25
【问题描述】:

我知道 NHibernate 并不打算进行批量插入,因为它比 SqlBulkCopy 慢大约 5 倍,但我决定使用它来简化代码。

但是,我的代码并没有慢 5 倍。它慢了 2400 倍。我正在插入大约 2500 条记录。我已经关闭了 log4net 日志记录。我在发布模式下运行它。我没有使用 id 生成器(我通过整数计数器在代码中指定它)。我正在使用无状态会话。我将批量大小设置为 100(我可以做得更多,但似乎没有帮助)。我尝试重新添加生成器,但将其类设置为“已分配”。

我没有插入任何子元素。我已经确认批量插入正在发生。

它还在调用 SELECT SCOPE_IDENTITY() 吗?但即使是这样,那仍然是一个荒谬的时间。

我不会做太多的批处理操作,所以我可以继续使用 SqlBulkCopy 进行这个过程,但我担心我的整个应用程序可能会运行得更快。

我没有 NHProf 的许可证,但我想知道现在是否可以下载试用版。

我将 NHibernate 3.3 GA 与 Syscache2 一起使用——但同样,我使用的是无状态会话。

您想查看任何 HBM、配置或代码吗?有什么建议吗?

谢谢

【问题讨论】:

  • 插入2500个对象需要多少时间?
  • 另外,您能否提供插入 2500 个对象和映射的代码?

标签: sql-server nhibernate bulkinsert


【解决方案1】:

因为它比 SqlBulkCopy 慢 5 倍

你一定是在开玩笑。

NHibrnate 进行插入。使用批量插入(即一个命令中不止一个插入语句),手写 - 我认为 NHibernate 不会这样做 - 我在一个特定项目中获得了大约 400 个插入。

使用 SqlBUlkCopy 我得到了 75000。

这不是 5 的因数,而是 187 的因数。

但是,我的代码并没有慢 5 倍。它慢了 2400 倍

不是 NHibernate 专家。记录连接 - 我假设 NHibernate 每批发送一个插入,这意味着处理速度很慢等,并且比我做的东西慢很多(我的文本开头)。

你到底是从哪里得到 5 倍系数的?这是一个错误的开始。

我没有做太多的批处理操作,所以这个过程我可以继续使用SqlBulkCopy,但是我很担心 我的整个应用程序可以运行得更快。

这是一个现实检查:当您需要极高的选择或插入速度时,不要使用 ORM。它们用于业务规则重的对象 - 业务对象。当您最终进行批量插入或读取时,您不要使用完整的 ORM。就这么简单。

如果您认为 SqlBUlkCopy 速度很快,请检查: * 在多个线程上运行多个 SqlBulkCopy... * ...惰性化到临时表中,然后 * ...使用一个insert into select语句将数据复制到最终表。

为什么?因为 SqlBulkCopy 对多线程有一些不好的锁定行为。这就是我得到它的原因。

AND:SqlBulkCopy 的 2500 行很低 - 设置开销很大(即在第 1 行之前)....所以你会得到更少的收益。我使用 50k 行批次。

NHibernate 在线级别上做了什么?

我已确认批量插入正在发生。

怎么样?您如何看待批量插入?

桌子上有触发器吗?

【讨论】:

  • 这里有一些数字:ayende.com/blog/4137/nhibernate-perf-tricks 即使他比实际高一个数量级,但差异是 30 倍而不是 187 倍。
  • 对我来说是 ;) 主要是在过去 2 年中,我主要进行 ETL 负载重排,并且性能非常关键....所以我现在在这方面做得很好。
  • 同上。我主要从事数据迁移工作,其中使用 sql 路由意味着神秘的列名和大量的compositeId 引用。调整过的 NHibernate 从来没有像你在这里展示的那样慢很多。等待 3 小时而不是 45 分钟,但节省 1 个月实施 etl 的工作是非常值得的。
  • @Firo,这是我在提出 5 倍索赔时使用的链接。 2500 行的 SqlBulkCopy 是多余的,但是当 NHibernate 在无状态会话中插入记录需要 3 分钟时,我必须做一些事情,SqlBulkCopy 需要 77 毫秒。我知道它正在执行批处理,因为如果我打开 log4net 和 SQL 日志记录,我可以看到这些批处理。我了解使用 ORM 的权衡取舍,但如果我配置或实现 ORM 的情况不佳,那不是 ORM 的错。桌子上没有触发器。我认为 2500 条记录的 3 分钟是过多的——每秒 13 次插入。我只是不知道从哪里开始寻找。
  • 同意。即使使用非批处理和个人事务,13 对于桌面来说也有点低。这速度太慢了。
【解决方案2】:

将 10000 个具有几个长字符串属性的对象插入到我的 devmashine 上的本地 mysql 数据库中:

StatelessSession:  4,6 seconds
Session:           5,7 seconds

【讨论】:

    【解决方案3】:

    我发现如果您执行许多插入操作,一级缓存会阻塞并很快导致其缓慢爬行。您可以尝试使用无状态会话,或者只是定期打开和关闭会话,即每 5 次插入。关闭会话当然会丢失诸如事务之类的东西。

    但最终,如果要插入的行数超过 100 行,我倾向于使用 SqlBulkCopy,速度要快很多倍。

    【讨论】:

    • session.Clear() 也会清理缓存但保持事务打开
    猜你喜欢
    • 2011-02-06
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    相关资源
    最近更新 更多