ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [EntityFramework Core] 간단히 알아본 Insert & Update 퍼포먼스 성능비교
    .NET/개념 및 유용한 팁 2021. 5. 30. 21:48
    반응형

    EntityFramework Core는 Microsoft에서 관리하는 오픈소스 ORM 라이브러리이다. ORM이 없기 전, 과거(라곤 하지만 현재도 유지되고 있다.)에는 쿼리 문자열을 작성하여 조회한 뒤, DataTable로 결과를 받아 처리하는 방식을 사용했었다. 모든 결과를 DataTable로 받기 때문에, 로직이 조금만 복잡해져도, 해당 DataTable이 가리키는 테이블이 무엇이고 어떤 필드가 어떤 유형(type)인지 제대로 파악하기 어려웠었다.

    EntityFramework 는 시스템이 사용할 테이블을 클래스(Class) 모델로 생성하고, 모델 객체를 통해 데이터를 조작하기 때문에 소스로직이 복잡해지더라도 클래스유형을 통해 분석이 용이하다는 장점이 있다.

     

    근데 써본사람들은 알겠지만, SQL쿼리보다 속도는 느린 편이다. 얼마나 느리고, 상황에 따라 어떻게 쓰는것이 더 유용한지 비교해볼 겸 테스트 소스코드를 준비해보았다.

     

    https://github.com/ddochea0314/EFCorePerfomanceTest

     

    ddochea0314/EFCorePerfomanceTest

    EFCore Insert & Update 속도 비교. Contribute to ddochea0314/EFCorePerfomanceTest development by creating an account on GitHub.

    github.com

     

    소스코드는 1천건의 데이터를 1건씩 처리하는 로직이며 해당 로직은 5번씩 반복 수행된다.

     

    Insert를 처리한 결과다

    Insert1은 Attach 상태 그대로 처리, Insert2는 처리 후 Detach 코드 추가, Insrt3은 SQL로 처리하였다. 예상대로 변경사항을 추적하는 EntityFramework 특성때문에 기본 처리방식이 Attach가 가장 느렸고, 추적을 끄기위해 Entry 상태값을 Detached로 변경한 Insert2가 그 다음, Query가 가장 빠른 순을 보였다.

     

    Insert1의 첫번째 시도가 1초정도 느리게 나오는데 이는 Entityframework가 프로그램 실행 직후 초기지연에 의한 것으로 실제론 다른 2~5번째 시도와 비슷하다고 봐도된다.

     

    코드는 아래와 같다.

    public static void Insert1()
    {
        var context = new Database_DevelopmentContext();
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (int i = 0; i < 1000; i++)
        {
            var user = new Users()
            {
                FirstName = Faker.Name.First(),
                LastName = Faker.Name.Last(),
                Email = Faker.Internet.Email()
            };
            context.Users.Add(user);
            context.SaveChanges();
    
        }
        stopwatch.Stop();
        Console.WriteLine("Insert1 seconds : " + stopwatch.Elapsed.TotalSeconds);
    }
    

     

    public static void Insert2()
    {
        var context = new Database_DevelopmentContext();
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (int i = 0; i < 1000; i++)
        {
            var user = new Users()
            {
                FirstName = Faker.Name.First(),
                LastName = Faker.Name.Last(),
                Email = Faker.Internet.Email()
            };
            context.Users.Add(user);
            context.SaveChanges();
            context.Entry(user).State = EntityState.Detached;
        }
        stopwatch.Stop();
        Console.WriteLine("Insert2 seconds : " + stopwatch.Elapsed.TotalSeconds);
    }
    

     

    public static void Insert3()
    {
        var context = new Database_DevelopmentContext();
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (int i = 0; i < 1000; i++)
        {
            var user = new Users()
            {
                FirstName = Faker.Name.First(),
                LastName = Faker.Name.Last(),
                Email = Faker.Internet.Email()
            };
            context.Database.ExecuteSqlRaw("INSERT INTO [dbo].[Users] ([firstName],[lastName],[email]) VALUES (@p0,@p1,@p2)", user.FirstName, user.LastName, user.Email);
        }
        stopwatch.Stop();
        Console.WriteLine("Insert3 seconds : " + stopwatch.Elapsed.TotalSeconds);
    }
    

    Update도 비슷한 결과를 보여주었다.

    이것으로 간략한 성능비교를 진행해보았다. Insert 또는 Update 이후에도 해당 객체를 계속 사용해야 한다면 기본적인 코드방식, Log와 같이 단순 기록이 목적이라면 Query를 이용해서 처리하면 될 듯 하다.

     

    Detach 처리는 어느쪽으로 사용해도 애매한듯 하다.


    .NET 6.0 과 함께 등장할 EF Core 6에서 큰 성능향상이 있다고 하는데, 나올때 다시 한번 비교해보겠다.

    반응형

    댓글

Designed by Tistory.