EF 경쟁 SaveChanges () 호출

.net c# entity-framework sqlbulkcopy transactions

문제

배치 처리 시스템을 구축 중입니다. Units 배치는 20-1000 개입니다. 각 Unit 는 본질적으로 모델의 계층 구조입니다 (하나의 주 모델과 많은 하위 모델). 내 작업에는 데이터베이스에 각 모델 계층 구조를 단일 트랜잭션으로 저장하는 작업이 포함됩니다 (각 계층 구조가 커밋되거나 롤백 됨). 유감스럽게도 EF 는 수천 개의 레코드를 포함 할 가능성 때문에 모델 계층 구조의 두 부분을 처리 할 수 ​​없었습니다.

이 문제를 해결하기 위해 수행 한 작업은 SqlBulkCopy 를 설정하여이 두 가지 잠재적 인 고수준 모델을 처리하고 EF 가 나머지 삽입 (및 참조 무결성)을 처리하도록했습니다.

일괄 처리 루프 :

foreach (var unitDetails in BatchUnits)
{
  var unitOfWork = new Unit(unitDetails);
  Task.Factory.StartNew(() =>
    {
      unitOfWork.ProcessX(); // data preparation
      unitOfWork.ProcessY(); // data preparation
      unitOfWork.PersistCase();
    });
}

단위:

class Unit
{
  public PersistCase()
  {
    using (var dbContext = new CustomDbContext())
    {
      // Need an explicit transaction so that 
      // EF + SqlBulkCopy act as a single block
      using (var scope = new TransactionScope(TransactionScopeOption.Required,
        new TransactionOptions() {
          IsolationLevel = System.Transaction.IsolationLevel.ReadCommitted
        }))
      {
        // Let EF Insert most of the records
        // Note Insert is all it is doing, no update or delete
        dbContext.Units.Add(thisUnit);
        dbContext.SaveChanges();  // deadlocks, DbConcurrencyExceptions here

        // Copy Auto Inc Generated Id (set by EF) to DataTables
        // for referential integrity of SqlBulkCopy inserts
        CopyGeneratedId(thisUnit.AutoIncrementedId, dataTables);

        // Execute SqlBulkCopy for potentially numerous model #1
        SqlBulkCopy bulkCopy1 = new SqlBulkCopy(...);
        ...
        bulkCopy1.WriteToServer(dataTables["#1"]);

        // Execute SqlBulkCopy for potentially number model #2
        SqlBulkCopy bulkCopy2 = new SqlBulkCopy(...);
        ...
        bulkCopy2.WriteToServer(dataTables["#2"]);

        // Commit transaction
        scope.Complete();
      }
    }
  }
}

지금 나는 근본적으로 바위와 어려운 장소 사이에 갇혀있다. IsolationLevelReadCommitted 설정하면 다른 Tasks EF INSERT 문 사이에 교착 상태가 발생합니다.

IsolationLevelReadUncommitted 설정하면 (어떤 SELECTs 수행하지 않으므로 괜찮을 것이라고 생각합니다) DbConcurrencyExceptionsDbConcurrencyExceptions .

DbConcurrencyExceptionsEntity Framework 에 대한 좋은 정보를 찾을 수 ReadUncommitted 가 본질적으로 EF 에 잘못된 "행 삽입"정보를 수신하게하는 ReadUncommitted 추측하고 있습니다.

최신 정보

INSERT를 수행하는 동안 실제로 교착 상태 문제를 일으키는 몇 가지 배경 정보는 다음과 같습니다.

http://www.microsoft.com/korea

이 같은 문제는 몇 년 전 Linq To SQL이 나왔을 때 Microsoft가 scope_identity ()를 선택하는 방법을 변경하여 해결 한 것처럼 보입니다. Entity Framework에서 같은 문제가 발생했을 때 SQL Server 문제가되는 이유가 무엇인지 잘 모르겠습니다.

수락 된 답변

이 문제는 여기에서 매우 잘 설명되어 있습니다. http://connect.microsoft.com/VisualStudio/feedback/details/562148/how-to-avoid-using-scope-identity-based-insert-commands-on-sql-server- 2005 년

기본적으로 내부 EF 문제입니다. 나는 Linq To SQL을 사용하기 위해 코드를 마이 그 레이션했다. 이제는 더 이상 잘 작동하지 않는다 (더 이상 ID 값에 대한 불필요한 SELECT 를하지 않는다).

Linq to Sql에서 똑같은 문제의 관련 인용문이 수정되었습니다.

테이블에 ID 열이 있으면 SQL에 대한 Linq는 이러한 테이블에 삽입하기에 매우 비효율적 인 SQL을 생성합니다. 테이블이 Order이고 identiy 열이 Id라고 가정합니다. 생성 된 SQL은 다음과 같습니다.

exec sp_executesql N'INSERT INTO [dbo]. [순서] ([Colum1], [Column2]) VALUES (@ p0, @ p1)

SELECT [t0]. [Id] FROM [dbo]. [순서] AS [t0] WHERE [t0]. [ID] = (SCOPE_IDENTITY ()) ', N'@ p0 int, @ p1 int, @ p0 = 124 , @ p1 = 432

'SELECT SCOPE_IDENTITY ()'를 사용하여 SCOPE_IDENTITY ()를 직접 반환하는 대신, 생성 된 SQL은 SCOPE_IDENTITY ()가 반환 한 값을 사용하여 Id 열에서 SELECT를 수행합니다. 테이블의 레코드 수가 많으면 삽입 속도가 크게 느려집니다. 테이블이 분할 될 때 문제는 더욱 심각해집니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.