首先使用EF代码和MVC 4获得更好的加载性能

时间:2013-07-15 16:55:30

标签: c# asp.net-mvc performance asp.net-mvc-4 profiling

我正在尝试在我的MVC 4项目中做出更好(=更快)的响应,主要是在Web Api部分。我添加了MiniProfiler以查看缓慢加载的问题,但我无法弄清楚。

                                                    duration (ms)   from start (ms)     query time (ms)
http://www.url.com:80/api/day?city=param (example)  1396.1             +0.0     1 sql   173.8
                                        logging     9.3              +520.9     
                                        EF query    4051.5           +530.2     2 sql   169.6 

然后当我再次尝试相同的网址时,我有这些数字:

 http://www.url.com:80/api/day?city=param (example) 245.6              +0.0     1 sql   50.6
                                         logging    8.6               +19.6     
                                         EF query   7.7               +28.3     

但是当我在2分钟后尝试它时,我再次得到了大数字,如第一个例子。

与加载主页索引相同:

http://www.blanskomenu.amchosting.cz:80/    333.0   +0.0    
         Controller: HomeController.Index   71.0    +286.8  
                          Find: Index   100.4   +387.8  
                     Render : Index     2468.1  +494.6 

这是我在第一个例子中使用Web Api的方法

[OutputCache(CacheProfile = "Cache1Hour", VaryByParam = "city")]
    public IEnumerable<RestaurantDayMealsView> GetDay(string city)
    {
        var profiler = MiniProfiler.Current;
        using (profiler.Step("logging"))
        {
            var logFile = new LogFile(System.Web.HttpContext.Current.Server.MapPath("~/Logs/"), DateTime.Today);
            logFile.Write(String.Format("{0},api/daymenu,{1}", DateTime.Now, city));
        }
        using (profiler.Step("EF query"))
        {
            var meals = repo.GetAllDayMealsForCity(city);
            if (meals == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }
            return meals;
        }
    }

和我的存储库方法:

    public IEnumerable<RestaurantDayMealsView> GetAllDayMealsForCity(string city)
    {
        return db.Restaurants
                 .Include(rest => rest.Meals)
                 .Where(rest => rest.City.Name == city)
                 .OrderBy(r => r.Order)
                 .AsEnumerable()
                 .Select(r => new RestaurantDayMealsView()
                     {
                         Id = r.Id,
                         Name = r.Name,
                         Meals = r.Meals.Where(meal => meal.Date == DateTime.Today).ToList(),
                         IsPropagated = r.IsPropagated
                     }).Where(r => r.Meals.Count > 0);
    }

我的家庭索引我只在控制器中:

    public ActionResult Index()
    {

        return View();
    }

所以我的问题是:

为什么索引的呈现需要这么长时间?我有默认网站所以我认为css和其他东西没有问题。 Network traffic from IE dev tools

不查询时,EF查询花了这么长时间?我该如何解决这些问题?

我正在查看这些链接:SO listASP.NET MVC Overview - performence我尝试了一些技巧并阅读了其他内容,但没有任何帮助我。问题可能与托管有关吗?或者在哪里?感谢

2 个答案:

答案 0 :(得分:0)

您的存储库方法看起来有1 + N查询问题。只有在您不修改集合时才使用Include进行优化(即在其上使用类似Where的内容)。执行此操作时,EF将从数据库中重新获取记录。您需要先将Meals强制转换为List,然后再运行Where子句。这将基本上冻结膳食的预选结果,然后在内存中而不是在数据库中过滤它们。

Meals = r.Meals.ToList().Where(meal => meal.Date == DateTime.Today).ToList(),

答案 1 :(得分:0)

<强> 1 Repository.GetAllDayMealsForCity()方法中:

return db.Restaurants
      .Include(rest => rest.Meals)
      .Where(rest => rest.City.Name == city)
      .OrderBy(r => r.Order)
      .AsEnumerable() // <-- Materiazling the query before projection
      .Select(r => new RestaurantDayMealsView()
          {
          Id = r.Id,
          Name = r.Name,
          Meals = r.Meals.Where(meal => meal.Date == DateTime.Today).ToList(),
          IsPropagated = r.IsPropagated
          }).Where(r => r.Meals.Count > 0);

您使用AsEnumerable()方法在Projecting结果之前致电Select。您必须记住AsEnumerable()导致查询“物化”(执行),并且因为您在Select方法之前调用它,您的查询不会将结果限制为所需的数据仅RestaurantDayMealsView(进一步投影在内存中的对象上完成,而不在数据存储上完成)。

此外,您的上一个Where也可以在AsEnumerable()方法之前附加。

<强> 2 第一次和第二次匹配之间的性能分析结果存在显着差异的原因可能是,在第一次实体框架查询来自SQL Server的数据之后,它会在内部将结果缓存到内存中以获得更好的性能。