EFCore.Visualizer – Visual Studio 내에서 Entity Framework Core 쿼리 계획 보기 | Giorgi Dalakishvili


EFCore.Visualizer - Visual Studio에서 Entity Framework Core 쿼리 실행 계획 확인하기

문제점 분석

Entity Framework Core의 성능 이슈

Entity Framework Core는 강력하고 기능이 풍부한 ORM으로 많은 애플리케이션을 지원하고 있습니다. EF Core를 통해 개발자는 강타입 LINQ 쿼리를 작성하고, 프레임워크가 이를 대상 데이터베이스용 SQL 쿼리로 변환합니다.

주요 성능 문제:

  • 스키마가 커지고 쿼리가 복잡해질수록 생성된 SQL이 최적화되지 않을 수 있음
  • 데이터베이스 인덱스 누락으로 인한 느린 쿼리 실행
  • 애플리케이션 성능 저하 초래

기존 해결 방법의 한계

EF Core는 생성된 쿼리를 로깅하고 느린 쿼리를 식별하는 쉬운 방법을 제공하지만, 실제 문제의 근본 원인을 파악하고 데이터베이스 엔진이 쿼리를 어떻게 실행하는지 확인하려면 쿼리 실행 계획을 탐색해야 합니다.

솔루션: EFCore.Visualizer

핵심 기능

EFCore.Visualizer는 Visual Studio 내에서 직접 쿼리 계획을 보고 분석할 수 있는 Visual Studio 확장 프로그램입니다.

주요 특징:

  • IQueryable<> 변수에 대한 디버거 시각화 도구 추가
  • 생성된 쿼리와 실행 계획을 동시에 표시
  • 중단점에서 IQueryable 변수에 마우스를 올리면 자동으로 작동
  • 모든 EF Core 쿼리 지원 (단순한 Where 절부터 복잡한 조인, 포함, 집계 쿼리까지)

지원 데이터베이스

모든 주요 RDBMS를 지원하며 데이터베이스 공급자를 자동으로 감지합니다:

  • SQL Server
  • PostgreSQL
  • MySQL
  • SQLite
  • Oracle

개발자 생산성 향상

Visual Studio와 데이터베이스 관리 도구 간의 전환 필요성을 제거하여 개발자의 내부 루프를 단축시킵니다. 기존 워크플로우 개선:

기존 방식:

  1. Visual Studio에서 쿼리 복사
  2. 데이터베이스 관리 도구로 전환
  3. 실행 계획 분석
  4. Visual Studio로 돌아가기
  5. 쿼리 수정
  6. 위 단계 반복

EFCore.Visualizer 사용:

  • Visual Studio에서 코드를 작성하고 디버깅하는 바로 그 위치에서 쿼리 계획 확인

설치 방법

Visual Studio 내에서 설치

  1. Visual Studio의 확장 관리자에서 “EFCore.Visualizer” 검색
  2. 설치 진행

Visual Studio Marketplace에서 설치

Visual Studio Marketplace에서 직접 다운로드 가능

사용법 및 실습 예제

샘플 모델 구성

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Post>().HasIndex(p => p.PublishedAt);
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public DateTimeOffset PublishedAt { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

기본 사용 방법

  1. 디버깅 시작
  2. IQueryable 인스턴스에 마우스 올리기
  3. 표준 디버거 툴팁에서 “Query Plan Visualizer” 클릭
  4. 생성된 SQL과 실행 계획 확인

성능 최적화 실습 사례

문제가 있는 쿼리 (비최적화):

var postsQuery = bloggingContext.Posts.Where(post => post.PublishedAt.Year == 2010);

문제점:

  • PublishedAt 컬럼에 인덱스가 있음에도 SQL Server가 이를 사용하지 않음
  • 생성된 쿼리가 PublishedAt 컬럼에서 연도를 추출하여 쿼리가 non-sargable이 됨
  • 실행 계획에서 테이블 스캔 발생

최적화된 쿼리:

var fromDate = new DateTime(2010, 1, 1);
var toDate = new DateTime(2011, 1, 1);

postsQuery = bloggingContext.Posts.Where(post => post.PublishedAt >= fromDate && post.PublishedAt < toDate);

개선 결과:

  • 쿼리 의미를 변경하지 않으면서도 성능 향상
  • 데이터베이스가 PublishedAt 인덱스 활용
  • 실행 계획에서 인덱스 탐색 사용

기술적 구현 원리

동작 메커니즘

  1. LINQ 쿼리를 ADO.NET 명령으로 변환
  2. 데이터베이스 엔진으로부터 실행 계획 가져오기
  3. 데이터베이스별 라이브러리를 사용한 계획 렌더링:
    • SQL Server: html-query-plan 라이브러리
    • PostgreSQL: pev2 라이브러리
    • 기타 데이터베이스: treeflex 라이브러리

제한사항 및 주의사항

지원하지 않는 쿼리 유형

  • 감소 종료 연산자가 사용된 쿼리 (Count(), Min(), First() 등)

성능 관련 제한사항

  • 매우 복잡한 쿼리나 느린 네트워크 연결 시 5초 제한 시간 초과 가능
  • 커스텀 시각화 도구의 5초 제한 시간을 연장할 방법 없음
  • 관련 이슈에 투표하여 개선 요청 가능

추가 학습 리소스

개발자 참고 자료

  • GitHub: 소스 코드 공개로 기여 및 작동 원리 탐색 가능
  • Visual Studio Toolbox: EFCore.Visualizer 심화 기능 에피소드 제공

실용적 활용 팁

  • Entity Framework Core 작업 시 쿼리 성능 이해를 위한 필수 도구
  • 느린 쿼리 분석 시 데이터베이스 실제 동작 파악에 유용
  • 개발 단계에서 성능 문제 조기 발견 가능

결론

모든 개발자가 경험하는 상황인 느린 쿼리를 마주했을 때, 데이터베이스가 실제로 무엇을 하고 있는지 궁금해하는 순간이 있습니다. Entity Framework Core로 작업하면서 쿼리 성능을 더 잘 이해하고 싶다면 EFCore.Visualizer를 사용해 보시기 바랍니다.

1개의 좋아요