C# 视图加载时间超过3分钟

C# 视图加载时间超过3分钟,c#,asp.net-mvc-4,nhibernate,code-first,C#,Asp.net Mvc 4,Nhibernate,Code First,使用asp.net MVC 4.0 c,Visual Studio 2012 professional 好的,我的控制器中有一个单独的操作结果,目的是获取许多不同的服务和模型,并将数据反规范化为列表以供视图显示,这是基于用户通过用于过滤数据的简单控件进行交互 整个网站已经从Webforms Sql项目迁移到使用内部CMS解决方案的MVC代码优先方法CMS基于Nop commerce和Orchard 现在,这个控制器函数运行得相当正常,直到我为每个传递的模块添加了代码。我最初想做的和我在旧项目中做

使用asp.net MVC 4.0 c,Visual Studio 2012 professional

好的,我的控制器中有一个单独的操作结果,目的是获取许多不同的服务和模型,并将数据反规范化为列表以供视图显示,这是基于用户通过用于过滤数据的简单控件进行交互

整个网站已经从Webforms Sql项目迁移到使用内部CMS解决方案的MVC代码优先方法CMS基于Nop commerce和Orchard

现在,这个控制器函数运行得相当正常,直到我为每个传递的模块添加了代码。我最初想做的和我在旧项目中做的一样,加入数据,然后交叉查询以获得非规范化的结果,然后使用

然而,当我首先从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;
    }

我不使用iquerable,而是列出历史记录,然后使用列表。 这大大缩短了加载时间,从6分钟缩短到15秒。 然而,正如大家所知,这还远远不够慢,唯一的结论是,这段代码必须位于选择列表中。那么有没有办法重做这个过程呢

var historyResults = quizHistoryQuery.ToList();
似乎您正在执行此查询并将结果存储在列表中,但下面几行显示了您正在执行的操作:

var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id));
导致再次执行查询

这只是突然发生的事情,我不知道这是否是导致你减速的原因。无论如何,请重新检查可能运行同一查询两次的任何实例,因为您似乎在几个地方执行此操作。考虑将结果存储在列表中,然后再与它们一起工作。
还可以考虑启动SQL探查器,看看生成的SQL查询是如何查找的,哪些查询占用的时间最长。p> 快速猜测:执行组查询时,数据仍处于查询形式。EF上的GroupBy的性能如此糟糕,以至于强制它先上市要快得多


答案很长,比快速猜测要短得多:简介

是的,我的第一个想法是删除tolist,但是这使它有了0的改进,因为它是在周末由lead添加的。您是否尝试过在这方面使用任何实际的性能度量工具?是否使用SQL Profiler和外部工具对查询进行了分析?快速更新,删除了历史记录结果旧的冗余代码,我认为这些代码没有什么不同,但看起来仍然没有什么不同。是的,我也听到了这些,尽管没有看到对我的页面时间的影响。这基本上是当我为模块输入代码时,它突然停了下来,这可能是我重复循环模块的结果吗?说真的,是profile!这并不难,也不可怕。如果您使用的是VisualStudio,您会发现它正在分析中。如果你不分析,你很可能会开始追逐鬼魂。如果您这样做,您将立即知道问题所在。如果这不能立即给出你的解决方案,你可以问更专注的人为什么x会慢,而不是整个故事的哪一部分可能导致它。从剖析器屏幕截图上看,OP实际上使用的是NHibernate而不是EF。是的,这显然是NHibernate在做的事情。不过我不知道,所以我不知道。遵循概要文件跟踪中的热路径可能是一个好主意——它将引导您找到代码中存在问题的部分。
var historyResults = quizHistoryQuery.ToList();
var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id));