EF 4.1에 엔터티를 삽입하는 것이 ObjectContext에 비해 느린 이유는 무엇입니까?


81

기본적으로 하나의 트랜잭션에 35000 개의 객체를 삽입합니다.

using(var uow = new MyContext()){
  for(int i = 1; i < 35000; i++) {
     var o = new MyObject()...;
     uow.MySet.Add(o);
  }
  uow.SaveChanges();
}

이것은 영원히 걸립니다! 기본 ObjectContext를 사용하면 (를 사용하여 IObjectAdapter) 여전히 느리지 만 약 20 초가 걸립니다. DbSet<>정사각형 시간이 걸리는 선형 검색을 수행하는 것 같습니다 .

이 문제를 본 다른 사람이 있습니까?


3
나는 어떻게 든 대답이 다음과 비슷할 것이라고 믿습니다. stackoverflow.com/questions/5917478/…
Ladislav Mrnka

답변:


128

Ladislav가 주석에서 이미 언급했듯이 성능을 개선하려면 자동 변경 감지를 비활성화해야합니다.

context.Configuration.AutoDetectChangesEnabled = false;

이 변경 감지는 DbContextAPI 에서 기본적으로 활성화됩니다 .

API DbContext와 다르게 작동 하는 이유 ObjectContext는 자동 변경 감지가 활성화 된 경우 API의 함수보다 DbContextAPI 의 더 많은 함수가 DetectChanges내부적으로 호출 ObjectContext되기 때문입니다.

여기DetectChanges 에서 기본적으로 호출 되는 함수 목록을 찾을 수 있습니다 . 그들은:

  • Add, Attach, Find, Local, 또는 Remove회원에DbSet
  • GetValidationErrors, Entry또는 SaveChanges회원DbContext
  • Entries에 방법DbChangeTracker

특히 귀하가 경험 한 성능 저하의 원인이되는 Add통화 DetectChanges.

이와 대조적으로 ObjectContextAPI는 위에서 언급 한 다른 해당 메서드를 호출 하지 않고 DetectChanges자동으로 호출 합니다 . 이것이의 기본 성능 이 더 빠른 이유 입니다.SaveChangesAddObjectObjectContext

DbContext많은 기능 에서이 기본 자동 변경 감지를 도입 한 이유는 무엇 입니까? 확실하지 않지만, 그것을 비활성화 DetectChanges하고 적절한 지점에서 수동으로 호출하는 것은 고급 으로 간주되고 응용 프로그램에 미묘한 버그를 쉽게 도입 할 수 있으므로 [it]를주의해서 사용하십시오 .


@Ladislav : 당신의 말이 맞아요 제가 삽입 문제를 찾고 있었기 때문에 이것을 찾지 못했습니다 :-(
Hartmut

설명 해주셔서 감사합니다. 실제로 context.Configuration.AutoDetectChangesEnabled = false를 호출했지만 Seed () 메서드에서 데이터베이스 생성 중에 수행했습니다. 이것이 기본값이 될 것이라고 생각했습니다. 각 인스턴스에 대해 호출해야한다는 사실을 몰랐습니다. 감사!
Hartmut

3
@Hartmut : 파생 된 DbContext의 생성자 내부에서 변경 감지를 비활성화 할 수 있으며 항상 비활성화 할 수 있습니다. 그러나 개인적으로 "미묘한 버그를 유발할 가능성이있다"는 말이 비활성화되었을 때 저를 불안하게 만듭니다. 기본적으로 변경 감지 기능이 있으며 성능 향상이 분명하고 문제를 일으키지 않는다고 생각되는 코드 블록에서만 비활성화합니다.
Slauma

동의합니다. 저는 애플리케이션의 성능에 중요한 부분을 테스트하고있었습니다. 프로덕션 코드에서는 대량 삽입 등과 같은 경우로 제한하는 것이 가장 좋습니다.
Hartmut

이 답변에 감사드립니다. 많은 정보가 있지만 이로 인해 추격전이 발생합니다!
Fred Wilson

12

EF 4.3 CodeFirst를 사용한 약간의 경험적 테스트 :

AutoDetectChanges = true : 23 초로 1000 개의 개체 제거

AutoDetectChanges = false로 1000 개의 개체 제거 : 11 초

AutoDetectChanges = true : 21 초로 개체 1000 개 삽입

AutoDetectChanges = false로 개체 1000 개 삽입 : 13 초


1
감사합니다 Zax. 질문에 따라 35,000 개의 결과는 무엇입니까? 당신은 성능이 차적으로 떨어질 것으로 tsates 원래의 질문에이를 볼 수 있습니다
다니엘 다이슨

9

.netcore 2.0에서는 다음으로 이동되었습니다.

context.ChangeTracker.AutoDetectChangesEnabled = false;


1

여기에서 찾은 답변 외에도. 데이터베이스 수준에서 추가하는 것보다 삽입해야하는 작업이 더 많다는 것을 아는 것이 중요합니다. 데이터베이스는 새 공간을 확장 / 할당해야합니다. 그런 다음 최소한 기본 키 인덱스를 업데이트해야합니다. 인덱스는 업데이트 할 때도 업데이트 될 수 있지만 훨씬 덜 일반적입니다. 외래 키가있는 경우 참조 무결성이 유지되는지 확인하기 위해 해당 인덱스도 읽어야합니다. 트리거는 동일한 방식으로 업데이트에 영향을 미칠 수 있지만 역할도 할 수 있습니다.

모든 데이터베이스 작업은 사용자 항목에서 시작된 일일 삽입 활동에서 의미가 있습니다. 그러나 기존 데이터베이스를 업로드하는 중이거나 많은 삽입을 생성하는 프로세스가있는 경우. 끝까지 연기하여 속도를 높이는 방법을 살펴볼 수 있습니다. 일반적으로 삽입하는 동안 인덱스를 비활성화하는 것이 일반적인 방법입니다. 경우에 따라 수행 할 수있는 매우 복잡한 최적화가 있지만 다소 압도적 일 수 있습니다.

일반적으로 삽입은 업데이트보다 오래 걸립니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.