저는 Entity Framework를 통해 응용 프로그램 데이터베이스로 대량 데이터 가져 오기/내보내기를 수행하기위한 명령 줄 도구가 있습니다. 이 도구는 새 레코드를 데이터베이스에 삽입하는 데는 잘 작동하지만 EF 잠금과 관련이있는 기존 레코드를 업데이트하려고 할 때 시간 초과 오류가 발생했습니다.EF 5 업데이트 시간 초과; 아마도 교착 상태로 인한 것일 수도 있습니다.
many 기타 posts (Entity Framework 및 교착 상태)에 대해 some을 읽었지만이 상황에 대한 답변이없는 것으로 보입니다. TransactionScope
내에서 가져 오기 코드를 래핑하고 SET TRANSACTION ISOLATION LEVEL
SQL 명령을 실행하려고했지만 어느 것도 시간 초과 문제를 해결하지 못했습니다.
SaveChanges
에 대한 단일 호출에서 얼마나 많은 엔티티가 업데이트되는지에 관계없이 시간 초과가 발생합니다. 아래의 샘플 코드에서는 배치 예외 크기를 1에서 500 사이의 값으로 설정했습니다. 항상 같은 예외가 throw됩니다.
다음은 예외 코드와 SQL Server 활동 모니터의 스크린 샷이 요약 된 업데이트 코드입니다.
EDMX 모델 (모델 우선)로 초기화되는 Entity Framework 5 DbContext 개체를 사용하고 있습니다.
using(var readContext = new MySourceEntities())
using(var readWriteContext = new MyTargetEntities())
{
var query = "SELECT ..."; // Determine which records to update
var keys = readContext.Database.SQLQuery<int>(query);
// Group the update into batches to improve performance. Batch()
// extension method from MoreLINQ
foreach (var batch in keys.Batch(BATCH_SIZE))
{
var sourceRecords = readContext
.AsNoTracking()
.Where(x => batch.Contains(x.SharedId))
.ToList();
var targetRecords = readWriteContext
.Where(x => batch.Contains(x.SharedId))
.ToLookup(x => x.SharedId);
foreach (var record in sourceRecords)
{
// Enforce a constraint on having only a single match
var target = targetRecords[record.SharedId].Single();
target.Field = record.Field;
}
readWriteContext.SaveChanges(); // <--- Timeout happens here
}
}
나는 명령 줄 응용 프로그램에서이 작업을 실행하고, 다음과 같이가 발생하는 특정 스택 추적은 다음과 같습니다
An error occurred while updating the entries. See the inner exception for details.
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at <snip>
An error occurred while updating the entries. See the inner exception for details.
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary`2 identifierValues, List`1 generatedValues)
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
SaveChanges
방법이 걸려 있지만, SQL 서버 활동 모니터 쇼 다음 쿼리는 모두 SUSPENDED
상태입니다. 빨간색 쿼리는 readContext
을 대상 데이터베이스에서 가져오고 파란색 쿼리는 readWriteContext
을 대상 데이터베이스에서 가져 왔습니다.
또한, 일시 중단 자체가 의심스러운, 단지 straighforward SELECT 및 UPDATE 명령을 보이지 않는 쿼리. 오류없이 수동으로 실행할 수 있습니다. 이 관련 될 것으로 보인다 있기 때문에 여기에
편집, 실행되는 query
조항의 세부 사항입니다. 쿼리는 데이터베이스간에 조인을 수행하여 SharedId
으로 레코드를 찾습니다. this page에서 sys.dm_os_waiting_tasks
쿼리를 실행하면 다음 표와 같습니다.
session_id wait_duration_ms wait_type blocking_session_id resource_description program_name text
55 15 ASYNC_NETWORK_IO NULL NULL EntityFramework <cross-db join query>
54 29310 LCK_M_IX 55 pagelock fileid=1... EntityFramework <update query>
쿼리의 내용은 나에게 가장 놀라운 관찰 쿼리가 여전히 활성화되어 있다는 점이다이
SELECT DB1.dbo.Table1.SharedId
FROM DB2.dbo.Table2 INNER JOIN DB1.dbo.Table1.SharedId
ON DB1.dbo.Table1.SharedId = DB2.dbo.Table2.SharedId
WHERE (
(DB1.dbo.Table1.Field1 <> DB2.dbo.Table2.Field1) OR
(DB1.dbo.Table1.Field2 <> DB2.dbo.Table2.Field2)
)
같다. readContext.Database.SQLQuery()
호출이 쿼리를 완료하지 못하는 이유는 무엇입니까? 이 대기 유형은 대개 응용 프로그램 오류를 나타내는 것처럼 들리지만이 동작을 트리거하는 방법은 확실하지 않습니다.