2017-12-22 16 views
2

이상한 현상이 발생하여 일반적인 ASP.NET MVC 응용 프로그램의 느린보기를 조사했습니다. 쿼리 중 하나가 명백한 이유없이 천천히 실행되고 있습니다. 문제의 LINQ 쿼리 (DbDbContext입니다) 같이 : 실제로동일한 SQL 쿼리가 실행 컨텍스트에 따라 빠르거나 느리다

var testResults = Db.CustomTestResults 
    .Include(tr => tr.TestMachine.Platform) 
    .Include(tr => tr.TestCase) 
    .Include(tr => tr.CustomTestResultAnalysis.Select(tra => tra.AnalysisOutcomeData)) 
    .Where(tr => tr.CustomTestBuildId == testBuild.Id) 
    .ToList() 
    .AsReadOnly(); 

특별한 아무것도. 필터 쿼리 결과 집합에 따라 최대 10에서 10000 개의 레코드 크기가 달라질 수 있습니다.

SSMS에서 실행되는 SQL 생성 쿼리 (LINQ 디버그 로그로 캡처 됨)는 빠르게 실행됩니다. 가장 큰 집합에는 약 2 초, 더 작은 집합에는 약 2 초가 걸립니다. 그러나 IIS에 의해 실행 이상한 일이. 쿼리가 ~ 1/100x 느린 속도로 실행되기 시작했습니다. 더 작은 것들은 실행하는데 약 10 초가 걸리고, 질의 실행 시간 초과 때문에 더 큰 것은 실패합니다. 다른 쿼리에 영향을 주는지 확신 할 수 없지만이 쿼리는 큰 데이터 집합을 처리하기 때문에 문제가 있음을 가장 분명하게 알 수 있습니다.

이 코드가 너무 혼란스럽지 않으므로이 코드는 오래 전부터 예상대로 완벽하게 실행되고있었습니다. 따라서 버그는 외부 요인에 의한 것 같습니다. 데이터베이스는 SQL Server 2014 SP2이고 EF는 IIS 7.5의 v6.2입니다.

어떤 분야의 아이디어가 좋을지 그리고 어떻게 조사 할 수 있을까요?

+0

사용 XEvent 프로파일 또는 (사용되지 않음) SQL 서버 프로파일 EF 쿼리 실행 및 * 실제 * 실행 계획과 관련된 이벤트를 캡처합니다. EF가 예기치 않은 설정을 지정하고 배치를 사용하여 데이터를로드하거나 느린 커서를 사용하는 경우가 있습니다. 확장 이벤트는 SQL Server 프로파일 러보다 훨씬 더 많이 캡처 할 수 있습니다. –

+0

EF로 인한 불행한 결정을 피하기 위해 쿼리를보고하기 위해 Dappert와 같은 microORM을 사용해보십시오. 아직보고하지 않은 경우보고 쿼리에 대한 변경 내용 추적을 사용하지 않도록 설정해야합니다. 단, 주문 문제가 발생할 수 있습니다. –

+0

BTW 동일한 문제가 발생했습니다. SSMS로 정상적으로 실행되는 쿼리는 몇 달 후 EF로 상당히 오래 걸리기 시작했습니다. 변경 추적 *이 비활성화되었습니다. –

답변

1

이 문제는 유사한 쿼리를 여러 번 실행 한 후 약간의 시간이 걸리는 SQL Server 최적화에서 발생했습니다. 이 문제는 원본 쿼리에 관련성이없는 변경으로 인해 감지 될 수 있습니다.

이 동작은 controlling query command options에 의해 적절히 완화 될 수 있습니다. EF 솔루션 중 하나는 demonstrated here입니다. 나는 따라서 SQL Server 엔진에 의해 최적화를 방지 쿼리 매번 랜덤이 방법을 사용하는 임시 "빠른 - 및 - 더러운"솔루션으로

:

private static IQueryable<CustomTestResult> RandomizeQuery(IQueryable<CustomTestResult> query) 
{ 
    const int minConditions = 1; 
    const int maxConditions = 5; 
    const int minId = -100; 
    const int maxId = -1; 

    var random = new Random(); 
    var conditionsCount = random.Next(minConditions, maxConditions); 
    for (int i = 0; i < conditionsCount; i++) 
    { 
     var randomId = random.Next(minId, maxId); 
     query = query.Where(test => test.Id != randomId); 
    } 

    return query; 
} 
0

SQL은 변경되지 않았지만 실행중인 플랫폼에 따라 문제가 발생하기 때문에 설정을 시작할 것입니다. 소음과 소음에 대한 훌륭한 참고 자료는 Erland Sommarskog가 작성한 것입니다. http://www.sommarskog.se/query-plan-mysteries.html

길지만 길게는 답변을 찾을 수있을 것입니다.

+1

이것은 질문을 던지지 않기 때문에 주석이어야합니다. * 데이터베이스 *는 동일하므로 설정이 중요하지 않아야합니다. EF 쿼리의 * 실제 * 실행 계획은 다를 수 있습니다. Erland의 기사는 이것에 대해 이야기하지 않습니다. –