【问题标题】:How to prevent a big EF INSERT blocking SELECT from a different app?如何防止大的 EF INSERT 阻止来自不同应用程序的 SELECT?
【发布时间】:2012-06-19 16:38:04
【问题描述】:

我有一个返回大量数据的进程(提交时要求大约 50-100k 个实体)

我在Commit(工作单元模式)之前执行所有Adds。我并没有在意提交实际需要多长时间——这个过程运行时间很长(几周),所以这里一分钟或者世界末日不是世界末日,而是在提交期间,使用相同抽象实体和上下文的第二个应用程序无法从数据库表中读取数据并最终超时。

如果我等到提交发生并尝试从应用 #2 再次读取,它几乎可以立即工作。

那么,我如何告诉 EF 在提交期间不要锁定表(大概是它在做什么?)?

关键代码在这里:

Dim DBTask = TaskRepository.Single(function(x) x.Id = CurrentTaskId)

''Task is a class which stores the results from the process before committing them
For Each Result In Task.Results
    Dim DbResult = TaskResultRepository.CreateInstance
    DbResult.Field1 = Result.Field1
    DbResult.Field2 = Result.Field2

    DbTask.Results.Add(DbResult)
Next
DbTask.JobStatus = Entities.JobStatuses.Completed
QLog.DebugFormat("Committing Task {1}: {0}", Task.Name, Task.Id)
UnitOfWork.Commit()
Tasks.Remove(Task)
QLog.InfoFormat("End Task {1}: {0}", Task.Name, Task.Id)

更糟糕的是,我目前缺乏工具,因为有人放错了 SQL Server 安装磁盘,所以没有 Management Studio/Performance Analyser,只有服务器资源管理器。

供参考,我的Repository(Of T As Entitybase).CreateInstance方法是:

Protected ReadOnly Entities As IDbSet(Of T)
Public Function CreateInstance() As T Implements Interfaces.IRepository(Of T).CreateInstance
    Dim Entity = Entities.Create(Of T)()
    With Entity
        .CreatedOn = Now
    End With
    Entities.Add(Entity)
    Return Entity
End Function

【问题讨论】:

  • @a_horse 不知道为什么我自己没有添加那个,谢谢
  • 我正要回答 SELECT 永远不应该被挂起的事务阻塞,但后来我看到你提到 SQL Server 哪种解释了这种行为。
  • 为了澄清,收集数据的后台线程可能需要数周才能运行。由于目前的架构方式,在流程完成之前不会提取数据。花费时间的不是提交(大约 10 分钟)

标签: .net sql-server entity-framework ef-code-first


【解决方案1】:

问题是您在单个 UOW 中导入所有内容,并且该过程需要数周才能完成(?)我真的希望这是一个错字,并且您在数周内都没有打开交易。一分钟太长,一周太荒谬。

你描述的是ETL的概念。提取、转换、加载。您将数据批量加载到数据库中的位置。您为此使用 EF,这意味着您使用的是针对小型工作单元进行了优化的 ORM。它们是用于 ETL 的工具。

第一个问题是使用 ORM 来执行 ETL。更好的选择是 Rhino.ETL 或 SSIS 来管理数据导入。 第二个问题是您在单个事务中导入的数据量。把它分成几块。一次可能有 1K、5K 条记录。这将有助于提高吞吐量并实际上减少导入所有数据所需的时间。

最后要调整的是,您将要手动控制事务锁定。听起来像使用了序列化级别锁定,这是最严格和最慢的。在事务完成之前不会发生其他任何事情。您可能会发现 ReadCommitted 是一个更好的锁定级别,允许在从另一个进程写入数据时进行读取。

但对于 EF 控制另一个操作过程。不,那是不可能的。

【讨论】:

  • 澄清一下,收集数据的过程需要数周时间。提交大约需要 10 分钟 - 但感谢有趣的链接,我会阅读
  • 好吧,这更有意义:) 10 分钟对于单个事务来说仍然是永恒的,但对于 ETL 操作来说,10 分钟并不是不合理的。我认为事务级别和批处理将是管理批量数据操作的关键。
  • 是的 - 但要清楚,我真的不介意提交是否需要 10 分钟 - 与过程的长度相比,它可以忽略不计。问题是,在提交期间我无法从同一个表中读取 = 后端进程的 Web UI 死掉了。明天我会去更改事务锁定
  • 10 分钟导入数据不是问题。单笔交易10分钟是个问题。以较小的块(从 500 或 1000 开始)导入这些数据,看看是否能解决问题。
猜你喜欢
  • 2013-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
  • 2020-05-08
相关资源
最近更新 更多