1

我有一个返回大量数据的过程(提交时需要 50-100k 个实体的顺序)

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

如果我等到提交发生并尝试从应用程序 #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
4

1 回答 1

1

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

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

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

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

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

于 2012-06-19T17:01:05.007 回答