다음을 통해 공유


효율적인 업데이트

일괄 처리

EF Core는 모든 업데이트를 단일 왕복으로 자동으로 일괄 처리하여 왕복을 최소화하는 데 도움이 됩니다. 다음을 고려합니다.

var blog = await context.Blogs.SingleAsync(b => b.Url == "http://someblog.microsoft.com");
blog.Url = "http://someotherblog.microsoft.com";
context.Add(new Blog { Url = "http://newblog1.microsoft.com" });
context.Add(new Blog { Url = "http://newblog2.microsoft.com" });
await context.SaveChangesAsync();

위의 내용은 데이터베이스에서 블로그를 로드하고 해당 URL을 변경한 다음 두 개의 새 블로그를 추가합니다. 이를 적용하려면 두 개의 SQL INSERT 문과 하나의 UPDATE 문이 데이터베이스로 전송됩니다. 블로그 인스턴스가 추가됨에 따라 EF Core는 이러한 변경 내용을 하나씩 보내는 대신 내부적으로 이러한 변경 내용을 추적하고 SaveChanges 호출할 때 단일 왕복으로 실행합니다.

EF가 한 번의 왕복에서 일괄 처리하는 문장 수는 사용 중인 데이터베이스 공급자에 따라 달라집니다. 예를 들어 성능 분석에 따르면 4개 미만의 문이 관련된 경우 SQL Server에 대한 일괄 처리의 효율성이 일반적으로 낮은 것으로 나타났습니다. 마찬가지로, SQL Server에서는 약 40개 문을 초과할 때 일괄 처리의 이점이 저하됩니다. 따라서 EF Core는 기본 설정으로 단일 일괄 처리에서 최대 42개의 문을 실행하며, 이보다 추가되는 문은 별도의 데이터베이스 왕복 과정을 통해 실행합니다.

사용자는 잠재적으로 더 높은 성능을 달성하기 위해 이러한 임계값을 조정할 수도 있지만 다음을 수정하기 전에 신중하게 벤치마크할 수 있습니다.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(
        @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True",
        o => o
            .MinBatchSize(1)
            .MaxBatchSize(100));
}

관련 있는 경우 ExecuteUpdate 및 ExecuteDelete 사용

모든 직원에게 급여 인상을 하고 싶다고 가정해 보겠습니다. EF Core에서 이에 대한 일반적인 구현은 다음과 같습니다.

foreach (var employee in context.Employees)
{
    employee.Salary += 1000;
}
await context.SaveChangesAsync();

이 코드는 완벽하게 유효한 코드이지만 성능 관점에서 수행하는 작업을 분석해 보겠습니다.

  • 모든 관련 직원을 로드하기 위해 데이터베이스 왕복이 수행됩니다. 급여만 필요한 경우에도 모든 Employees 행 데이터를 클라이언트에 제공합니다.
  • EF Core의 변경 내용 추적은 엔터티를 로드할 때 스냅샷을 만든 다음 해당 스냅샷을 인스턴스와 비교하여 변경된 속성을 확인합니다.
  • 일반적으로 두 번째 데이터베이스 왕복은 모든 변경 내용을 저장하기 위해 수행됩니다(일부 데이터베이스 공급자는 변경 내용을 여러 라운드트립으로 분할합니다). 이 일괄 처리 동작은 각 업데이트에 대해 왕복을 수행하는 것보다 훨씬 낫지만 EF Core는 여전히 직원당 UPDATE 문을 보내고 데이터베이스는 각 문을 별도로 실행해야 합니다.

EF Core 7.0부터 ExecuteUpdateAsyncExecuteDeleteAsync 메서드를 사용하여 동일한 작업을 훨씬 더 효율적으로 수행할 수 있습니다.

await context.Employees.ExecuteUpdateAsync(s => s.SetProperty(e => e.Salary, e => e.Salary + 1000));

이렇게 하면 다음 SQL 문이 데이터베이스로 전송됩니다.

UPDATE [Employees] SET [Salary] = [Salary] + 1000;

UPDATE 데이터베이스에 실제 데이터를 로드하거나 보내지 않고 EF의 변경 내용 추적 기계를 사용하지 않고 단일 왕복으로 전체 작업을 수행하므로 추가 오버헤드가 발생합니다. 자세한 내용은 ExecuteUpdateExecuteDelete참조하세요.

아직 ExecuteUpdateExecuteDelete지원하지 않는 이전 버전의 EF Core를 사용하거나 이러한 메서드에서 지원되지 않는 복잡한 SQL 문을 실행하려는 경우에도 SQL 쿼리를 사용하여 작업을 수행할 수 있습니다.

context.Database.ExecuteSql($"UPDATE [Employees] SET [Salary] = [Salary] + 1000");

SaveChanges ExecuteUpdate / ExecuteDelete간의 차이점에 대해 자세히 알아보려면 데이터 저장에 대한 개요 페이지 참조하세요.