상세 컨텐츠

본문 제목

Entity Framework Core - Best Practices (모범사례) - C# & .NET

본문

.NET을 하시는 분들이면 Entity Framework을 쓰시죠.  ADO.NET 에서 EF Core (Entity Framework Core)로 넘어온 지 오랜 세월이 지났지만 아직도 완전히 EF Core를 제대로 알고 쓰는 사례가 많이 없는 것 같아서 몇 가지 팁을 올려봅니다.

EF Core는 예전의 ADO에서의 데이터 테이블을 클래스화 시켜서. NET 코딩을 하기가 아주 수월하게 만들어 주죠.  처음 입문을 할시에는 생각의 변화를 많이 주어야 해서 두려운 감도 없지는 않지만 이용하기 시작하면 너무 편하다는 느낌을 줍니다.  데이터 테이블의 몇 번째 데이터가 무슨 칼럼이냐 라는 생각을 안 해도 되고요. 
 

반응형

 
하지만 생각이 바뀌는 만큼 테크놀로지도 아주 다릅니다.  그래서 튜닝이나 여기저기 다르게 생각해야 할 부분이 많습니다.   깊게 빠져들어 가면 더욱 복잡하지만 몇 가지 간단한 팁만 알고 있어도 EF Core를 쉽게 사용할 수 있죠.


1.  Pooling을 쓰지 말 것

.NET Core 애플리케이션을 구성하고 EF Core를 쓰게 되면 자동적으로 풀링을 쓰게 됩니다.  여러 메서드에서 DB Context를 만들 때 처음에 만들어진 DB Context를 재이용을 하게 되죠.  하지만 이 부분은 메모리 Leak 이 되어서 나중에는 애플리케이션 작동이 원활하지 않게 됩니다.  이건 옛날 컴퓨터 사양이 지금처럼 좋지 않을 때에 유리한 거였고 지금 컴퓨터는 매번 데이터를 부를 때마다 새로이 DB Context를 생성해도 무관합니다.  그래서 매번 새롭게 DB Context 인스턴스를 생성을 해 주세요.


2.  AsNoTracking()을 사용

EF Core에서 데이터를 불러오면 자연적으로 Change Tracking 이 발동을 합니다.  이게 무엇이냐 하면 불러온 데이터가 변화하는 디테일들을 다 저장을 하는 기능입니다.  그래서 바꾼 데이터를 저장하는 커맨드를 넣으면 자동으로 트랙킹 한 데이터를 안전하게 저장을 하지요.  하지만 이 기능은 꼭 필요할 시에만 활성화를 시키는 게 좋습니다.  리소스를 먹기 때문이죠.  많은 데이터를 가지고 와서 요리조리 바꾸고 하다 보면 DB Context가 몇 기가를 잡아먹고 있을 때도 있습니다.  그렇게 되면 EF Core에 관한 기능들이 아주 느려집니다.
 
이 기능은 아래와 같이 데이터를 불러올 때 자동으로 활성화가 되어 있습니다.

var students = dbContext.Students.Where(p => p.Active).ToList();

하지만 만약에 이 students라는 리스트를 에디트를 안 하고 보이기로만 쓰일 거라면 아래같이 트래킹을 비활성화시켜주시면 아주 좋습니다.

var students = dbContext.Students.Where(p => p.Active).AsNoTracking().ToList();

AsNoTracking() 이 들어가면 데이터를 수정할 수가 없다는 단점이 있지만 리스트에 보여주기만 하는 목적이면 아주 앱의 성능에 플러스 효과를 가져다주죠.  아래의 마이크로 소프트에서 보여주는 데이터를 보시면 50% 정도의 스피드 향상이 있습니다.  아주 중요한 팁이에요 

데이터 속도 비교 - Microsoft

 

728x90

3.  FromSqlRaw()이나 FromSqlInterpolated() 사용

EF Core는 링크언어로 쿼리를 만들죠.  하지만 복잡한 쿼리를 링크로 만들다 보면 쿼리 성능이 아주 나쁠 수가 종종 있습니다.  그럴 시엔 SQL 언어로 써주시면 나을 때가 있습니다.  EF Core 버전이 바뀌면서 이 부분이 많이 달라졌는데요 EF Core 최신 버전에는 다음과 같이 SQL 언어를 Inject 할 수가 있습니다.

var paramAge = 15;
var students = dbContext.Students.FromSqlRaw('SELECT Id, FirstName, LastName FROM Students WHERE Age > ' + paramAge.ToString()).ToList();

FromSqlRaw 보다 FromSqlInterpolated 가 더 안전하다고 합니다.  왜냐하면 패러미터가 들어가는 부분을 FromSqlRaw는 보완 해커의 코드 인젝션을 보완하지 못하고 FromSqlInterpolated는 그럴 수 있다는 장점이 있다고 하네요.  그럼 위의 같은 코드를 어떻게 하면 FromSqlInterpolated로 다시 쓸 수 있을까요?

var paramAge = 15;
var students = dbContext.Students.FromSqlInterpolated($'SELECT Id, FirstName, LastName FROM Students WHERE Age > { paramAge }').ToList();

4.  Streaming vs Buffering (스트리밍 vs 버퍼링)

데이터를 가지고 올 때 두 가지 방법이 있습니다. 
 
버퍼링은 .ToList() 나 .ToArray() 로 끝을 내면 모든 데이터가 메모리에 버퍼링이 되는 식이죠.  가지고 온 데이터의 양이 적으면 이렇게 해도 상관은 없지만 아주 많게 되면 버퍼링에 많은 양의 리소스가 차지하고 있게 되고 앱의 성능이 떨어지게 됩니다.  
 
스트리밍이 버퍼링을 보완하는 기능인데요.  .ToList() 나 .ToArray()로 끝내지 않으면 Enumerable의 상태가 되어 그 안의 하나하나의 데이터를 버퍼링 할 수 있는 기능이죠.  그러면 리소스도 버퍼링이 돼있는 데이터만 차지하게 되고요.  한 번에 처리하는 속도는 버퍼링보다는 느리지만 앱이 차지하는 리소스의 양이 적어서 앱이 크래시가 된다거나 그런 상황을 막을 수가 있습니다.

// 버퍼링의 예제
var blogsList = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
var blogsArray = context.Posts.Where(p => p.Title.StartsWith("A")).ToArray();

// 스트리밍의 예제 1 - 루프로 돌려서 하나하나 버퍼링:
foreach (var blog in context.Posts.Where(p => p.Title.StartsWith("A")))
{
    // ...
}

// 스트리밍의 예제 2 - AsEnumerable을 사용하여 스트리밍:
var doubleFilteredBlogs = context.Posts
    .Where(p => p.Title.StartsWith("A")) // AsEnumerable 전 - 서버에서 필터링이 되어서 데이터가 들어옴
    .AsEnumerable()
    .Where(p => SomeDotNetMethod(p)); // AsEnumerable 후 - 들어온 데이터를 클라이언트에서 필터링

수고하셨습니다.  즐거운 코딩되세요!


도움이 되셨거나 즐거우셨다면 아래의 ❤️공감버튼이나 구독버튼을 눌러 주세요~  감사합니다

 

 

728x90
반응형

관련글 더보기