2012-10-07 2 views
1

지난 며칠 동안 다음 쿼리를 최적화하는 방법과 많은 행운이없는 방법을 파악하려고했습니다. 바로 지금 내 테스트 db는 중첩 된 데이터가 거의없는 약 300 개의 레코드를 반환하지만 실행하는 데 4-5 초가 걸리고 LINQ에서 생성되는 SQL은 너무 길기 때문에 여기에 포함하기에는 너무 길다. 어떤 제안이라도 대단히 감사 할 것입니다.엔티티 프레임 워크 시간 초과

이 쿼리를 요약하면 현재 상태가있는 클라이언트 목록의 다소 평평한 "스냅 샷"을 반환하려고합니다. 당사자는 역할이있는 하나 이상의 클라이언트 (ASPNET 역할 공급자)를 포함하고, 업무 일지는 당사자의 모든 클라이언트에 대한 마지막 1 개의 업무 일지 항목을 반환하며, 작업도 마찬가지이며 LastLoginDate, 따라서 OrderBy 및 FirstOrDefault 기능을 포함합니다.

Guid userID = 'some user ID' 
var parties = Parties.Where(p => p.BrokerID == userID).Select(p => new 
{ 
ID = p.ID, 
Title = p.Title, 
Goal = p.Goal, 
Groups = p.Groups, 
IsBuyer = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")), 
IsSeller = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "seller")), 
Journal = p.Clients.SelectMany(c => c.Journals).OrderByDescending(j => j.OccuredOn).Select(j=> new 
    { 
     ID = j.ID, 
     Title = j.Title, 
     OccurredOn = j.OccuredOn, 
     SubCatTitle = j.JournalSubcategory.Title 
    }).FirstOrDefault(), 
LastLoginDate = p.Clients.OrderByDescending(c=>c.LastLoginDate).Select(c=>c.LastLoginDate).FirstOrDefault(), 
MarketingPlanCount = p.Clients.SelectMany(c => c.MarketingPlans).Count(), 
Task = p.Tasks.Where(t=>t.DueDate != null && t.DueDate > DateTime.Now).OrderBy(t=>t.DueDate).Select(t=> new 
    { 
     ID = t.TaskID, 
     DueDate = t.DueDate, 
     Title = t.Title 
    }).FirstOrDefault(), 
Clients = p.Clients.Select(c => new 
    { 
     ID = c.ID, 
     FirstName = c.FirstName, 
     MiddleName = c.MiddleName, 
     LastName = c.LastName, 
     Email = c.Email, 
     LastLogin = c.LastLoginDate 
    }) 
}).OrderBy(p => p.Title).ToList() 

답변

0

나는있는 OrderBy가 큰 차이를 만들 수 있기 전에 또는 투사 한 후 오는 순서 같은 작은 것들로, 우리에게 약간의 단서를 제공 할 수있는 SQL을 게시 생각합니다.

하지만 별개의 쿼리에서 클라이언트를 추출해보십시오. 그러면 쿼리가 간단해질 것입니다. 그리고 는 투사하기 전에 다른 저널과 같은 테이블과 작업을 포함하고이 쿼리에 미치는 영향을보기 : 모든 경우에

 
    //am not sure what the exact query would be, and project it using ToList() 
    var clients = GetClientsForParty(); 

    var parties = Parties.Include("Journal").Include("Tasks") 
      .Where(p=>p.BrokerID == userID).Select(p => { 

    .... 
    //then use the in-memory clients 
    IsBuyer = clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")), 
    ... 
    } 
    ) 

EF profiler를 설치하고 쿼리가 어떻게 영향을 받는지를 보라. EF는 놀라 울 정도로 조용 할 수 있습니다. 투영 전에 OrderBy를 배치하는 것과 같은이 FirstOrDefault 또는 SingleOrDefault에 대해 모두 동일한 효과가 있습니다.

LoweredRoleName에서 검색하는 경우 기본 사항으로 돌아가서 쿼리가 빠르도록 인덱싱되었는지 확인하십시오 (EF는 이후 커버 리지 인덱스를 사용하지 않을 수 있기 때문에 쓸모 없게 될 수도 있음). 다른 많은 열을 쿼리하고 있습니다).

또한 쿼리는 데이터를 변경하지 않고 데이터를 변경하기 때문에 엔티티 추적 기능을 끄는 것을 잊지 말고 성능을 향상시킬 수도 있습니다.

마지막으로 SQL 쿼리를 직접 작성하고 익명 형식이 아닌 ViewModel에 프로젝션 할 수 있다는 것을 잊지 마십시오 (필자는 올바른 방법으로 생각합니다). 따라서 Flatten을 포함하는 PartyViewModel이라는 클래스를 만듭니다 당신이 후하다보고, 당신의 손으로 만들어진 SQL

 
//use your optimized SQL query that you write or even call a stored procedure 
db.Database.SQLQuery("select * from .... join .... on"); 

내가 EF 주위 이러한 문제에 대한 blog post을 쓰고 그것을 사용합니다. 포스트는 아직 끝나지 않았지만, 모두 인내심을 가지고이 트릭 중 일부를 사용하고 그 효과를 관찰 (그리고 측정)하면 원하는대로 도달 할 것입니다.