2014-01-06 3 views
2

asp.net MVC 4.0 C#, Visual Studio 2012 professional 사용.로드 3 분 이상 걸리는보기

알았어, 내 컨트롤러에 하나의 작업 결과가 있는데, 그 목적은 다양한 서비스와 모델을 사용하고 표시 할보기 목록으로 데이터를 비정규 화하는 것입니다. 이는 사용자 상호 작용을 기반으로합니다. 간단한 컨트롤을 통해 데이터를 필터링하는 데 사용됩니다.

전체 사이트가 Webforms Sql 프로젝트에서 내부 CMS 솔루션 (CMS는 Nop commerce 및 Orchard를 기반으로 함)을 사용하여 MVC 코드 첫 번째 방법으로 마이그레이션되었습니다.

이제이 컨트롤러 기능은 각 모듈에 대한 코드를 추가 할 때까지 상당히 잘 작동했습니다. 원래는 이전 프로젝트에서했던 것과 똑같은 일을하고 싶었고 데이터를 합친 다음 정규화되지 않은 결과를 사용하여 교차 분석을 사용했습니다.

그러나 SQL에서 코드로 처음 전송할 때 교차 쿼리를 모방 할 수 있는지는 확실하지 않았습니다.

이로 인해 많은 루프가 생성되었습니다. 여기에는 컨트롤러 동작 방법과 비 동작이 있습니다.

public ActionResult Index(UsersModel model) 
    { 
     model.DateTo = model.DateTo.AddDays(1); 

     if (model.DateFrom == null || model.DateTo == null || model.DateFrom == DateTime.MinValue || model.DateTo == DateTime.MinValue.AddDays(1)) 
     { 
      // default to last 30 days 
      model.DateFrom = _clock.UtcNow.AddDays(-30); 
      model.DateTo = _clock.UtcNow; 
     } 

     var userQuery = _academyUserService.Query() 
      .Where(x => x.Activity.DateRegistered >= model.DateFrom && x.Activity.DateRegistered <= model.DateTo); 

     var quizCompletedQuery = _quizService.QueryQuizHistoryCompleted() 
      .Where(x => x.DateCompleted >= model.DateFrom && x.DateCompleted <= model.DateTo); 

     var quizHistoryQuery = _quizService.QueryHistory() 
      .Where(x => x.DateCompleted >= model.DateFrom && x.DateCompleted <= model.DateTo); 

     var moduleQuery = _moduleService.Query() 
      .Where(x => x.Published); 

     //admin country selected, null = global 
     if (_moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"] != null) 
     { 
      userQuery = userQuery.Where(x => x.UserCountry.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString()); 
      quizCompletedQuery = quizCompletedQuery.Where(x => x.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString()); 
      quizHistoryQuery = quizHistoryQuery.Where(x => x.Module.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString()); 
      moduleQuery = moduleQuery.Where(x => x.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString()); 
     } 

     if (!string.IsNullOrEmpty(model.Name)) 
     { 
      userQuery = userQuery.Where(x => x.FirstName.Contains(model.Name) || x.Surname.Contains(model.Name)); 
     } 

     if (!string.IsNullOrEmpty(model.AccountType)) 
     { 
      userQuery = userQuery.Where(x => x.AccountType.ToString() == model.AccountType); 
     } 

     if (!string.IsNullOrEmpty(model.Company)) 
     { 
      userQuery = userQuery.Where(x => x.BusinessName == model.Company);//placeholder intefering with this? 
     } 

     if (!string.IsNullOrEmpty(model.Code)) 
     { 
      userQuery = userQuery.Where(x => x.RegistrationCode.Contains(model.Code)); 
     } 

     if(true)//cant condition an Iquery as its not a list...)//temp 
     { 
      //quizCompletedQuery = quizCompletedQuery.Where(x => x.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString()); 
     } 

     //new code 
     var groupedModules = moduleQuery 
      .OrderBy(x => x.DisplayOrder) 
      .ToList() 
      .GroupBy(x => x.Country) 
      .SelectMany(group => group.Select((x, i) => new { Index = i, Module = x })) 
      .GroupBy(anon => anon.Index) 
      .Select(group => group.Select(x => x.Module).ToList()) 
      .ToList(); 

     var historyResults = quizHistoryQuery.ToList(); 

     //my old code 
     PrepareBusinessNames(model); 

     var usersToModel = userQuery.ToList().Select(x => 
     { 

      bool thisHistoryPassed1 = false; 
      bool thisHistoryPassed2 = false; 
      bool thisHistoryPassed3 = false; 
      bool thisHistoryPassed4 = false; 

      if (groupedModules.Count > 0) 
      { 
       var module1 = groupedModules[0]; 
       var moduleIds1 = module1.Select(y => y.Id).ToList(); 
       var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id)); 
       thisHistoryPassed1 = thisHistory1.Any(_quizService.IsHistoryPassed); 
      } 

      if (groupedModules.Count > 1) 
      { 
       var module2 = groupedModules[1]; 
       var moduleIds2 = module2.Select(y => y.Id).ToList(); 
       var thisHistory2 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds2.Contains(y.Module.Id)); 
       thisHistoryPassed2 = thisHistory2.Any(_quizService.IsHistoryPassed); 
      } 

      if (groupedModules.Count > 2) 
      { 
       var module3 = groupedModules[2]; 
       var moduleIds3 = module3.Select(y => y.Id).ToList(); 
       var thisHistory3 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds3.Contains(y.Module.Id)); 
       thisHistoryPassed3 = thisHistory3.Any(_quizService.IsHistoryPassed); 
      } 

      if (groupedModules.Count > 3) 
      { 
       var module4 = groupedModules[3]; 
       var moduleIds4 = module4.Select(y => y.Id).ToList(); 
       var thisHistory4 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds4.Contains(y.Module.Id)); 
       thisHistoryPassed4 = thisHistory4.Any(_quizService.IsHistoryPassed); 
      } 

      return new UsersSearchModel 
      { 
       UserID = x.Id, 
       Name = x.FirstName, 
       Surname = x.Surname, 
       Company = x.BusinessName, 
       AccountType = x.AccountType.ToString(), 
       UserCode = x.RegistrationCode, 
       VideosViewed = "", //x.VideoActivity.ToString(), 
       Module1 = thisHistoryPassed1, 
       Module2 = thisHistoryPassed2, 
       Module3 = thisHistoryPassed3, 
       Module4 = thisHistoryPassed4, 
       Module1Url = thisHistoryPassed1 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png"), 
       Module2Url = thisHistoryPassed2 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png"), 
       Module3Url = thisHistoryPassed3 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png"), 
       Module4Url = thisHistoryPassed4 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png") 
      }; 
     }).ToList(); 

     var jsonSerialiser = new JavaScriptSerializer(); 
     var jsonString = jsonSerialiser.Serialize(usersToModel);//or is it model? or a list of model? 
     model.REFACTOR_ForJson = jsonString; 

     return View(model); 
    } 

    #region utilities 

    [NonAction] 
    private UsersModel PrepareBusinessNames(UsersModel model) 
    { 
     if (_moServices.Authoriser.Authorise(DefaultPermissions.AccessAdminPanel)) 
     { 
      var listItems = _academyUserService.GetAllBusinessNames().Select(x => 
      { 
       return new SelectListItem 
       { 
        Value = x, 
        Text = x 
       }; 
      }).OrderBy(x => x.Value) 
      .ToList(); 

      model.CurrentBusinessNames = new SelectList(listItems, "Value", "Text"); 
     } 

     return model; 
    } 

사용자 목록을 반환하고 필터를 기반으로 모듈을 나타내는 4 개의 열이있는 목록을 표시하고 전달되었는지 여부는 알 수 있습니다.

내가 말했듯이, 통과 또는 통과되지 않은 부울 값을 얻기위한 코드를 추가하면 내 쿼리가 촬영되어 오랜 시간이 걸립니다.

기존 코드를 수정하여 문제를 해결할 수있는 방법이 있습니까? 아니면 교차 쿼리와 비슷한 방법을 사용하여 기능을 다시 작성할 수있는 솔루션입니까?

당신의 팁 주셔서 감사합니다!

업데이트 ::

을 heres 프로파일 결과, 난 임 여기에서 무엇을 찾고 메신저 확실하지 전에를 사용한 적이있다.

Profile

은 부품 및 진술하면 다른이 definatly SEMS의 주요 느린 반응의 원인으로 "(groupedModules.Count> 0)의 경우를"주석. 그래서 이전에 물어 보았 듯이 결과를 얻는 더 좋은 방법이 있습니까?

if (groupedModules.Count > 0) 
      { 
       var module1 = groupedModules[0]; 
       var moduleIds1 = module1.Select(y => y.Id).ToList(); 
       var thisHistory1 = historyResults.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id)); 
       thisHistoryPassed1 = thisHistory1.Any(_quizService.IsHistoryPassed); 
      } 

대신 iquerable를 사용하여

if (groupedModules.Count > 0) 
      { 
       var module1 = groupedModules[0]; 
       var moduleIds1 = module1.Select(y => y.Id).ToList(); 
       var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id)); 
       thisHistoryPassed1 = thisHistory1.Any(_quizService.IsHistoryPassed); 
      } 

을 대체 ::

업데이트는, 내가 역사는 다음 대신 목록을 사용 tolist. 이렇게하면로드 시간이 6 분에서 15 초로 크게 단축됩니다. 그러나 이것이 모두 여전히 느린 것으로 알고 있으므로 유일한 결론은이 코드가 선택 목록에 있어야한다는 사실입니다. 프로세스를 다시 할 수있는 방법이 있습니까?

var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id)); 

쿼리를 다시 실행 원인 :

+0

yeh 내 첫 번째 문장은 tolist를 제거하는 것이었지만이 방법으로는 0 번의 개선이있었습니다. 주말에 선두에 추가 된대로이 문장을 남겼습니다. – lemunk

+0

실제 성능 측정 도구를 사용해 보셨습니까? SQL 프로파일 러 및 외부 도구를 사용하여 쿼리를 프로파일 링 했습니까? –

답변

2

빠른 추측 : 그룹 쿼리를 수행 할 때 데이터는 여전히 쿼리 형식입니다. EF의 GroupBy()는 끔찍한 성능을 발휘하여 처음으로 강제로 나열하는 것이 훨씬 빠릅니다.

빠른 추측보다 훨씬 짧은 긴 대답 : 프로필!

+0

yeh 내 페이지 시간에 영향을 볼 수 없었지만이 역시 들었습니다. 이것은 기본적으로 모듈에 대한 코드를 넣었을 때 갑자기 거의 멈추었을 때 모듈과 모듈을 반복적으로 반복 할 수 있습니까? – lemunk

+1

진지하게, 프로필! 그것은 열심히 또는 무서운 :). Visual Studio를 사용하는 경우 분석 아래에서 찾을 수 있습니다. 프로필을 작성하지 않으면 유령을 쫓기 시작할 것입니다. 그렇게하면 문제가있는 곳을 즉시 알 수 있습니다. 그것이 당신에게 당신의 솔루션을 곧바로 줄지 못한다면, 전체 이야기의 어느 부분이 그것을 일으키는 것이 아닌, 왜 느리게 느낄 수 있는지 더 집중할 수있게 요청할 수 있습니다. – Martijn

+0

예, 프로필! 추측을 그만두고 알아 내기 시작하십시오! –

1
var historyResults = quizHistoryQuery.ToList(); 

는 당신이이 쿼리를 실행하고 몇 줄 당신이하고있는 노호 아직 목록에 결과를 저장하는 것 같다.

이것은 단지 튀어 나온 것일 뿐이며 속도가 느려지는지 전혀 알 수 없습니다. 어쨌든 동일한 쿼리를 두 번 실행할 수있는 경우를 다시 확인하십시오. 두 곳에서이 작업을 수행하고있는 것으로 보입니다. 그 결과를 목록에 저장하고 이후에 작업하는 것이 좋습니다. 또한 SQL 프로파일 러를 시작하고 생성 된 SQL 쿼리가 어떤 모습으로 나타나는지 그리고 어느 것이 가장 많은 시간이 걸리는지보십시오.

+0

팁을 주셔서 감사합니다 – lemunk

+0

빠른 업데이트, 내 생각에 역사적인 결과 (오래된 중복 코드를 생각합니다)하지만 여전히 031 차이를 만들었습니다. – lemunk

관련 문제