【问题标题】:Performance decrease after each batch processed by a background job后台作业处理每个批次后性能下降
【发布时间】:2017-05-18 13:18:15
【问题描述】:

我注意到我的后台作业在每批之后表现更差。基本上,作业需要巨大的 csv 文件,然后以 250 条记录为单位更新数据库中的相关记录。在每批之后,我都会重新创建数据库上下文以保持 ObjectContext 整洁,但这无济于事,而且看起来每批之后一切都变得越来越慢。我的工作是:

  1. 从文件中读取 250 条记录
  2. 创建 DbContext
  3. 然后对于每条记录
  4. 从数据库中获取对应的实体
  5. 更新属性(反射)
  6. 处理 250 条记录时 - SaveChanges

因此,当作业开始时,4. 大约需要 170 毫秒,5 需要大约 6 毫秒。

50个批次后,4个需要~430ms,5个需要~500ms。

有人可以解释一下这里发生了什么吗?

更新。 事实证明,这不是hangfire 故障 - 所以我删除了所有对hangfire 的引用。

问题似乎出在 DbContext 上,尽管我正在重新创建 DbContext 处理在每批之后仍然需要更长的时间。我也错过了 5 的一件事。 - 每次都需要更长的时间打电话给dbContext.Entry(entity).Property("Guid").IsModified = false:

//for each 250 items
var dbContext = new MyDbContext();

dbContext.Configuration.ValidateOnSaveEnabled = false;

foreach (var item in items)
{
    var entity = dbContext.MyItems
        .Include(x => x.SomeProp) // lots of these
        .FirstOrDefault(BuildFilterFrom(item)); //after each batch this taking longer (starting from 170ms and then after 50 batches it takes 430ms)

    //set entity propties from item
    //...

    dbContext.Entry(entity).Property("Guid").IsModified = false //after each batch this also taking longer (starting from 6ms and then after 50 batches it takes 500ms)
}
dbContext.SaveChanges();

【问题讨论】:

  • 你能提供执行这六个步骤的代码片段吗?
  • 检查此进程生成的 SQL 脚本。我最近遇到了类似的情况,Entity Framework 创建了可怕的 SQL(实际上并不是它的错),并且因为我多次执行它,它正在炸毁查询优化器。由于您没有进行批量抓取,这减少了我的场景应用的机会,但我仍然会查看数据库连接。
  • 运行时系统资源是什么样的(潜在的内存泄漏)?
  • @Nico 我用更多细节更新了我的问题。
  • @krillgar 感谢您的评论,我认为您可能是对的 - db 调用一定有问题..

标签: c# performance entity-framework batch-processing


【解决方案1】:

根据您的更新,我认为最好的办法是在更改 Guid 属性时忽略它们。您应该能够将.Where() 添加到您的属性集合中,以使用该名称消除它们。这样可以节省设置属性以及更改 IsModified 属性的微秒时间。

【讨论】:

  • 感谢您的回答,这肯定会给我一些改进,但是 FirstOrDefault 调用仍然存在问题。我开始重新编写代码以使用来自 EntityFramework.Extended 的更新(以避免加载实体),但是我想了解为什么 FirstOrDefault 调用一直变慢。
  • 这可能与您构建的过滤器有关,以及您拉回了多少相关对象。正如我在对该问题的评论中所说,请查看生成的 SQL。在一次调用数据库中获取所有对象可能会更好,但您可能不会。通过这些大型批量流程,您终于进入了使用 SQL Server Profiler 进行检查和“包括实际执行计划”是一个巨大好处的领域。
【解决方案2】:

从您发布的信息中提供任何信息有点困难。当然,hangfire 工作不会累,但根据工作类型和重复、异常等,hangfire 会序列化数据并将其保存在数据库中并获取再次来自 DB。

您是否遵循http://docs.hangfire.io/en/latest/best-practices.html 此处描述的最佳做法。您还可以使用日志记录来了解工作的哪一部分需要时间,使用跟踪日志级别来了解挂火是否导致问题

http://docs.hangfire.io/en/latest/configuration/configuring-logging.html

【讨论】:

  • 感谢您的建议,这不是挂火故障。 dbcontext 或我对 db 的调用有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
  • 2013-06-14
  • 2014-04-12
相关资源
最近更新 更多