使用EF6 + MVC5渲染网页时性能不佳。为什么?

时间:2014-05-28 12:32:13

标签: c# asp.net-mvc entity-framework

我使用.NET framework 4.5.1,MVC 5和EF 6开发了一个Web应用程序。数据存储在MySQL数据库中。 问题是表演真的很糟糕,我找不到原因。有些页面需要几秒钟(最多10秒)才能完全加载!

我试图在网上找到一些建议,但是它们没有什么改进。

例如,以下Controller从数据库中获取用户列表并将其传递给View。

public class UserController : Controller
{
    // GET: /User/
    public async Task<ActionResult> Index()
    {
        using (AuthorDbContext db = new AuthorDbContext())
        {
            return View(await db.Users.OrderBy(u => u.Surname)
                                        .ThenBy(u => u.Name)
                                        .Include(u => u.Company)
                                        .Include(u => u.Department)
                                    .ToListAsync());
        }
    }

    // [...]
}

View将用户的详细信息打印到HTML表格中(使用jQuery的DataTable plugin)。

@model IEnumerable<Author.Models.User>
@using Author.Helpers

<div class="geco-button-container">
    @ButtonHelper.CreateButton(Url.RouteUrl("New User"), "Add a new user")
</div>

<table id="longTable" class="longTable">
    <thead>
        <tr>
            <th></th>
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Surname)
            </th>
[...]
        </tr>
    </thead>
    <tbody>
    @foreach (var item in Model) {
        <tr@(item.QuittedOn != null && item.QuittedOn.Value < DateTime.Now ? " class=user_dismissed" : "")>
            <td class="tableButton">
                @ButtonHelper.ViewButton(Url.RouteUrl("View User", new RouteValueDictionary {{ "id", item.id }}), "", "Details")
                @if (item.canBeEdited)
                {
                    @ButtonHelper.EditButton(Url.RouteUrl("Edit User", new RouteValueDictionary {{ "id", item.id }}), "", "Edit")
                    @ButtonHelper.DeleteButton(Url.RouteUrl("Delete User", new RouteValueDictionary {{ "id", item.id }}), "", "Delete")
                }
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Surname)
            </td>
[...]
            <td>
                @if (item.Department != null)
                {
                    @Html.RouteLink(item.Department.Code.ToString(), "View Department", new RouteValueDictionary { { "id", item.DepartmentId } }, new Dictionary<string,object> { { "title", item.Department.Description.ToString() } })
                }
            </td>
        </tr>
    }
    </tbody>
</table>
@section Scripts {
    @Scripts.Render("~/Scripts/DataTables-1.9.4/media/js/jquery.dataTables.min.js")
    @Scripts.Render("~/Scripts/longTable.js")
}

当我访问此页面时,需要5到10秒才能完成加载698个用户的列表。

我已经安装了Glimpse,它说问题似乎是生成页面的呈现。

Glimpse - HTTP tab

Glimpse - Execution tab

Glimpse - Timeline

正如您所看到的,我实施了一些可以提高性能的技巧,例如:

  • 使用RouteLinkRouteUrl代替ActionLinkActionUrl
  • 使用async来电
  • 禁用除RazorViewEngine以外的所有视图引擎(在Global.asax中)

我在本地计算机上使用调试模式运行应用程序。有人建议将选项debug="false"设置为web.config,但我也已将其发布在使用该选项运行的Web服务器上,问题仍然存在。

许多人抱怨实体框架的速度很慢,但是他们通常谈论几百毫秒,而在我的情况下它需要几秒钟 - 这在Web场景中真的是不可接受的!

有什么问题?我做错了什么?


更新

我已经安装了dotTRACE,这是显示用户列表的页面上的结果。

dotTRACE on a page

正如您所看到的,瓶颈在于Microsoft框架。

MappingDataUtilities类是什么?它的目标是什么?它的功能如何引用Json,Css,TagName,Selectors等......?

我的代码从不明确地调用这些东西。如何改善他们糟糕的表现?

1 个答案:

答案 0 :(得分:0)

我强烈建议您将ViewModel与DataModel分离。当这两个是相同的东西时,它意味着将所有内容暴露给您的ViewModel,即使您只需要一些字段。我建议创建一个只包含您感兴趣的字段的新ViewModel,然后更新您的EF查询,只选择您需要的字段,而不是在许多表上执行SELECT *。我认为这将有助于提高绩效。