0

我试图在我的 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 和其他东西没有问题。来自 IE 开发工具的网络流量

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

我正在查看这些链接:SO 列表ASP.NET MVC 概述 - 性能,我尝试了一些技巧并阅读了其他一些技巧,但没有什么对我有太大帮助。问题可能与托管有关吗?还是在哪里?谢谢

4

2 回答 2

0

看起来您的存储库方法中有一个 1+N 查询问题。Include仅当您不修改集合时才优化使用(即在其上使用类似的东西)Where。当您这样做时,EF 将从数据库中重新获取记录。您需要先转换Meals为 a List,然后运行您的Where子句。这实际上将冻结 Meals 的预选结果,然后在内存中而不是在数据库中过滤它们。

Meals = r.Meals.ToList().Where(meal => meal.Date == DateTime.Today).ToList(),
于 2013-07-15T17:06:25.467 回答
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()之前调用。您必须记住,这导致查询“物化”(执行),并且因为您在方法之前调用它,所以您的查询不会将结果限制为仅需要的数据(进一步的投影是在 in -内存对象而不是数据存储)。ProjectingSelectAsEnumerable()SelectRestaurantDayMealsView

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

2. 第一次和第二次命中之间的分析结果存在显着差异的原因可能是,在 Entity Framework 第一次从 SQL Server 查询数据后,它在内部将结果缓存在内存中以获得更好的性能。

于 2013-07-15T17:10:38.450 回答