[EFCore] Entityframework에서 느린 쿼리 알아내는법

https://medium.com/@sudipdevdev/how-to-detect-and-log-slow-queries-in-entity-framework-core-e2ab71024849

 

How to Detect and Log Slow Queries in Entity Framework Core

As applications grow in complexity, performance bottlenecks can become a significant challenge, particularly with database queries…

medium.com

 

요즘 EntityFramework사용해서 작업 중입니다. EntityFramework는 쿼리 로그 옵션을 넣어서 프로그램을 동작하면 실행하는 모든 쿼리에 대한 로그를 볼 수 있습니다. 이는 편하지만 프로그램에서 사용하는 모든 쿼리를 봐야 하기 때문에 오래 걸리거나 문제가 있는 쿼리만 추출하기는 어려운 점이 있습니다.

 

그래서 느린 쿼리 관련 구글링 하다가 느린 쿼리만 찍는 코드를 찾아 공유합니다. 

 


 

 

⌨ SlowQueryDetectionHelper 클래스 추가 

- SlowQueryThreshlodInMillisecond를 5로 초기화했기 때문에 5 ms 이상 걸리는 쿼리들은 워닝으로 찍어냅니다. 

- 🔥 DbCommandInterceptor 란? 
: EF Core에서 실행되는 모든 SQL을 가로채서 수정하거나, 로깅할 수 있음. 

public class SlowQueryDetectionHelper : DbCommandInterceptor
{
    private const int SlowQueryThresholdInMilliSecond = 5;
    
    public override ValueTask<DbDataReader> ReaderExecutedAsync(DbCommand command, CommandExecutedEventData eventData, DbDataReader result, CancellationToken cancellationToken = default)
    {
        if (eventData.Duration.TotalMilliseconds > SlowQueryThresholdInMilliSecond)
        {
        	//여기서 각자한테 맞는 로그를 찍으면됨, 저는 NLog로 찍었습니다. 
            Log.Warn($"Slow Query Detected. {command.CommandText}  TotalMilliSeconds: {eventData.Duration.TotalMilliseconds}");
        }
        return base.ReaderExecutedAsync(command, eventData, result,cancellationToken);
    }
    public override DbDataReader ReaderExecuted(DbCommand command, CommandExecutedEventData eventData, DbDataReader result)
    {
        if (eventData.Duration.TotalMilliseconds > SlowQueryThresholdInMilliSecond)
        {
            Log.Warn($"Slow Query Detected. {command.CommandText}  TotalMilliSeconds: {eventData.Duration.TotalMilliseconds}");
        }
        return base.ReaderExecuted(command, eventData, result);
    }

 

그리고 이 SlowQueryDataDetectionHelper를 최초에 초기화 시 option에 걸어서 사용하면 됩니다. 

   //Register DbContext      
    services.AddDbContext<YourDBContext>(options =>
    {
        options.UseSqlServer(configuration.GetConnectionString(your-connection-string),
        providerOption =>
        {
            providerOption.CommandTimeout(300);
        });
        //only on development environment
        options.EnableSensitiveDataLogging();
        options.AddInterceptors(new SlowQueryDetectionHelper());
    });

    return services;
}

 

그러면 프로그램 실행 시 5초 이상 걸리는 쿼리는 쿼리 내용과 수행시간이 찍힙니다. 

이때 주의할 점은 이 쿼리 자체가 굉장히 중요한 정보일 수도 있으니 프로그램 실행환경에 맞춰 처리해야 합니다.